home *** CD-ROM | disk | FTP | other *** search
/ Windows Game Programming for Dummies (2nd Edition) / WinGamProgFD.iso / pc / DirectX SDK / DXSDK / extras / Direct3D / Tools / Maya40 / xporttranslator.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-10-08  |  144.3 KB  |  5,892 lines

  1. // IDEAS FOR FUTURE: 
  2. //        - option to export only selected items
  3. //        - skinning for bezier patches
  4. //        - support for single-sided vs. double sided faces
  5.  
  6. // TODO:
  7. //    - Rend & Poses load wrong (due to skinning followed by polyFaceSmoothing)
  8. //    - Hidden objects are exported  ("visibility" && "lodVisibility" && (!"overrideEnabled" || "overrideVisibility"))
  9. //    - Tom hall's 2nd cable jiggles
  10. //    - tesselation loses skinning & material info
  11.  
  12. // debug options
  13. #define ALWAYS_TESSELATE_NURBS
  14. //#define NO_INTERMEDIATE_OBJECTS
  15.  
  16. #include "xportTranslator.h"
  17.  
  18. #include <iostream.h>
  19. #include <assert.h>
  20. #include <conio.h>
  21. #include <math.h>
  22. #include <dxfile.h>                // DirectX File Format
  23. #include <initguid.h>
  24. #include <rmxfguid.h>
  25. #include <rmxftmpl.h>
  26. #include "xskinexptemplates.h"    // Additional X-file Templates
  27. #include <MDt.h>                // Dt API
  28. #include "MyDt.h"
  29. // Maya API
  30. #include <maya/MSimple.h>
  31. #include <maya/MObject.h>
  32. #include <maya/MDagPath.h>
  33. #include <maya/MPlug.h>
  34. #include <maya/MSelectionList.h>
  35. #include <maya/MColor.h>
  36. #include <maya/MMatrix.h>
  37. #include <maya/MQuaternion.h>
  38. #include <maya/MEulerRotation.h>
  39. #include <maya/MTime.h>
  40.  
  41. #include <maya/MIntArray.h>
  42. #include <maya/MFloatArray.h>
  43. #include <maya/MFloatVectorArray.h>
  44. #include <maya/MFloatPointArray.h>
  45. #include <maya/MPointArray.h>
  46. #include <maya/MObjectArray.h>
  47. #include <maya/MDagPathArray.h>
  48. #include <maya/MPlugArray.h>
  49.  
  50. #include <maya/MAnimControl.h>
  51. #include <maya/MAnimUtil.h>
  52.  
  53. #include <maya/MFnPlugin.h>
  54. #include <maya/MFnDagNode.h>
  55. #include <maya/MFnTransform.h>
  56. #include <maya/MFnIKJoint.h>
  57. #include <maya/MFnMesh.h>
  58. #include <maya/MFnNurbsSurface.h>
  59. #include <maya/MFnLambertShader.h>
  60. #include <maya/MFnBlinnShader.h>
  61. #include <maya/MFnPhongShader.h>
  62. #include <maya/MFnSkinCluster.h>
  63. #include <maya/MFnWeightGeometryFilter.h>
  64. #include <maya/MFnMatrixData.h>
  65. #include <maya/MFnSet.h>
  66.  
  67. #include <maya/MItSelectionList.h>
  68. #include <maya/MItDependencyGraph.h>
  69. #include <maya/MItDependencyNodes.h>
  70. #include <maya/MItDag.h>
  71. #include <maya/MItGeometry.h>
  72. #include <maya/MItMeshPolygon.h>
  73.  
  74. const GUID* g_aIds[] = {&DXFILEOBJ_XSkinMeshHeader,
  75.                       &DXFILEOBJ_VertexDuplicationIndices,
  76.                       &DXFILEOBJ_SkinWeights};
  77.  
  78.  
  79.  
  80. // GLOBALS
  81.  
  82. CArrayTable g_Arrays;        // used to keep some arrays (e.g. shape names, transforms, etc.) persistent during the export
  83. MDagPathArray g_AddedPaths;    // used to save DAG path of an exported shape (so that we can later load its animation)
  84. // the following are export options
  85. DXFILEFORMAT g_FileFormat;    
  86. bool g_bExportAnimation;
  87. bool g_bKeyframeAnimation;
  88. bool g_bAnimateEverything;
  89. bool g_bRelativeTexFile;
  90. bool g_bExportPatches;
  91. int g_iFrameStep;
  92. int g_iFlipU;
  93. int g_iFlipV;
  94.  
  95.  
  96. int g_iCount;
  97.  
  98.  
  99.  
  100.  
  101.  
  102. HRESULT    AddAnim
  103.         (
  104.             SAnim*                    pAnim, 
  105.             LPDIRECTXFILEDATA        pAnimSetObject, 
  106.             LPDIRECTXFILESAVEOBJECT    pxofSave
  107.         ) 
  108. {
  109.     HRESULT hr = S_OK;
  110.     LPDIRECTXFILEDATA pAnimDataObject          = NULL;
  111.     LPDIRECTXFILEDATA pQuaternionKeyDataObject = NULL;
  112.     LPDIRECTXFILEDATA pScaleKeyDataObject      = NULL;
  113.     LPDIRECTXFILEDATA pPositionKeyDataObject   = NULL;
  114.     PBYTE pbPositionKeyData   = NULL;
  115.     PBYTE pbScaleKeyData      = NULL;
  116.     PBYTE pbQuaternionKeyData = NULL;
  117.     UINT iKey;    // counter
  118.     UINT cbQuaternionKeySize = sizeof(DWORD)                                                // keyType
  119.                                 + sizeof(DWORD)                                                // nKeys
  120.                                 + pAnim->m_nKeys 
  121.                                     * (sizeof(DWORD) + sizeof(DWORD) + 4 * sizeof(float));    // keys[nKeys]
  122.     UINT cbScaleKeySize      = sizeof(DWORD)                                                // keyType
  123.                                 + sizeof(DWORD)                                                // nKeys
  124.                                 + pAnim->m_nKeys 
  125.                                     * (sizeof(DWORD) + sizeof(DWORD) + 3 * sizeof(float));    // keys[nKeys]
  126.     UINT cbPositionKeySize   = sizeof(DWORD)                                                // keyType
  127.                                 + sizeof(DWORD)                                                // nKeys
  128.                                 + pAnim->m_nKeys 
  129.                                     * (sizeof(DWORD) + sizeof(DWORD) + 3 * sizeof(float));    // keys[nKeys]
  130.     PBYTE    pbPositionKeyCurr;
  131.     PBYTE    pbScaleKeyCurr;
  132.     PBYTE    pbQuaternionKeyCurr;
  133.  
  134.  
  135.  
  136.     hr = pxofSave->CreateDataObject(TID_D3DRMAnimation, NULL, NULL, 0, NULL, &pAnimDataObject);
  137.     if (FAILED(hr))
  138.     {
  139.         cout << "AddAnim(): Could not create pAnimDataObject." << endl;
  140.         goto e_Exit;
  141.     }
  142.  
  143.     pbPositionKeyCurr = pbPositionKeyData = new BYTE[cbPositionKeySize];
  144.     if (NULL == pbPositionKeyData)
  145.     {
  146.         hr = E_OUTOFMEMORY;
  147.         cout << "AddAnim(): Could not allocate memory for pbPositionKeyData." << endl;
  148.         goto e_Exit;
  149.     }
  150.  
  151.     pbScaleKeyCurr = pbScaleKeyData = new BYTE[cbScaleKeySize];
  152.     if (NULL == pbScaleKeyData)
  153.     {
  154.         hr = E_OUTOFMEMORY;
  155.         cout << "AddAnim(): Could not allocate memory for pbScaleKeyData." << endl;
  156.         goto e_Exit;
  157.     }
  158.  
  159.     pbQuaternionKeyCurr = pbQuaternionKeyData = new BYTE[cbQuaternionKeySize];
  160.     if (NULL == pbQuaternionKeyData)
  161.     {
  162.         hr = E_OUTOFMEMORY;
  163.         cout << "AddAnim(): Could not allocate memory for pbQuaternionKeyData." << endl;
  164.         goto e_Exit;
  165.     }
  166.  
  167.  
  168.     // keyType
  169.     WRITE_DWORD(pbQuaternionKeyCurr,    ((DWORD)0));
  170.     WRITE_DWORD(pbScaleKeyCurr,            ((DWORD)1));
  171.     WRITE_DWORD(pbPositionKeyCurr,        ((DWORD)2));
  172.  
  173.     // nKeys
  174.     WRITE_DWORD(pbQuaternionKeyCurr,    ((DWORD)pAnim->m_nKeys));
  175.     WRITE_DWORD(pbScaleKeyCurr,            ((DWORD)pAnim->m_nKeys));
  176.     WRITE_DWORD(pbPositionKeyCurr,        ((DWORD)pAnim->m_nKeys));
  177.  
  178.     // keys[nKeys]
  179.     for (iKey = 0; iKey < pAnim->m_nKeys; iKey++) 
  180.     {
  181.         // time
  182.         WRITE_DWORD(pbQuaternionKeyCurr,    ((DWORD)pAnim->m_aKeys[iKey].m_iFrame));
  183.         WRITE_DWORD(pbScaleKeyCurr,            ((DWORD)pAnim->m_aKeys[iKey].m_iFrame));
  184.         WRITE_DWORD(pbPositionKeyCurr,        ((DWORD)pAnim->m_aKeys[iKey].m_iFrame));
  185.  
  186.  
  187.         // nValues
  188.         WRITE_DWORD(pbQuaternionKeyCurr,    ((DWORD)4));
  189.         WRITE_DWORD(pbScaleKeyCurr,            ((DWORD)3));
  190.         WRITE_DWORD(pbPositionKeyCurr,        ((DWORD)3));
  191.  
  192.         // values
  193.         WRITE_FLOAT(pbQuaternionKeyCurr,    pAnim->m_aKeys[iKey].m_afQuaternion[0]);
  194.         WRITE_FLOAT(pbQuaternionKeyCurr,    pAnim->m_aKeys[iKey].m_afQuaternion[1]);
  195.         WRITE_FLOAT(pbQuaternionKeyCurr,    pAnim->m_aKeys[iKey].m_afQuaternion[2]);
  196.         WRITE_FLOAT(pbQuaternionKeyCurr,    pAnim->m_aKeys[iKey].m_afQuaternion[3]);
  197.  
  198.         WRITE_FLOAT(pbScaleKeyCurr,    pAnim->m_aKeys[iKey].m_afScale[0]);
  199.         WRITE_FLOAT(pbScaleKeyCurr,    pAnim->m_aKeys[iKey].m_afScale[1]);
  200.         WRITE_FLOAT(pbScaleKeyCurr,    pAnim->m_aKeys[iKey].m_afScale[2]);
  201.  
  202.         WRITE_FLOAT(pbPositionKeyCurr,    pAnim->m_aKeys[iKey].m_afPosition[0]);
  203.         WRITE_FLOAT(pbPositionKeyCurr,    pAnim->m_aKeys[iKey].m_afPosition[1]);
  204.         WRITE_FLOAT(pbPositionKeyCurr,    pAnim->m_aKeys[iKey].m_afPosition[2]);
  205.     }
  206.  
  207.     hr = pxofSave->CreateDataObject(TID_D3DRMAnimationKey, NULL, NULL, cbQuaternionKeySize, pbQuaternionKeyData, &pQuaternionKeyDataObject);
  208.     if (FAILED(hr))
  209.     {
  210.         cout << "AddAnim(): Could not create pQuaternionKeyDataObject." << endl;
  211.         goto e_Exit;
  212.     }
  213.  
  214.  
  215.     hr = pxofSave->CreateDataObject(TID_D3DRMAnimationKey, NULL, NULL, cbScaleKeySize, pbScaleKeyData, &pScaleKeyDataObject);
  216.     if (FAILED(hr))
  217.     {
  218.         cout << "AddAnim(): Could not create pScaleKeyDataObject." << endl;
  219.         goto e_Exit;
  220.     }
  221.  
  222.  
  223.     hr = pxofSave->CreateDataObject(TID_D3DRMAnimationKey, NULL, NULL, cbPositionKeySize, pbPositionKeyData, &pPositionKeyDataObject);
  224.     if (FAILED(hr))
  225.     {
  226.         cout << "AddAnim(): Could not create pPositionKeyDataObject." << endl;
  227.         goto e_Exit;
  228.     }
  229.  
  230.  
  231.     hr = pAnimDataObject->AddDataReference(pAnim->m_szName, NULL);
  232.     if (FAILED(hr))
  233.     {
  234.         cout << "AddAnim(): Could not add data reference to pAnimDataObject." << endl;
  235.         goto e_Exit;
  236.     }
  237.  
  238.     hr = pAnimDataObject->AddDataObject(pQuaternionKeyDataObject);
  239.     if (FAILED(hr))
  240.     {
  241.         cout << "AddAnim(): Could not add pQuaternionKeyDataObject to pAnimDataObject." << endl;
  242.         goto e_Exit;
  243.     }
  244.  
  245.  
  246.     hr = pAnimDataObject->AddDataObject(pScaleKeyDataObject);
  247.     if (FAILED(hr))
  248.     {
  249.         cout << "AddAnim(): Could not add pScaleKeyDataObject to pAnimDataObject." << endl;
  250.         goto e_Exit;
  251.     }
  252.  
  253.     
  254.     hr = pAnimDataObject->AddDataObject(pPositionKeyDataObject);
  255.     if (FAILED(hr))
  256.     {
  257.         cout << "AddAnim(): Could not add pPositionKeyDataObject to pAnimDataObject." << endl;
  258.         goto e_Exit;
  259.     }
  260.  
  261.  
  262.  
  263.     hr = pAnimSetObject->AddDataObject(pAnimDataObject);
  264.     if (FAILED(hr))
  265.     {
  266.         cout << "AddAnim(): Could not add pAnimDataObject to pAnimSetObject." << endl;
  267.         goto e_Exit;
  268.     }
  269.  
  270.  
  271.  
  272. e_Exit:
  273.  
  274.     delete[] pbQuaternionKeyData;
  275.  
  276.     delete[] pbScaleKeyData;
  277.     
  278.     delete[] pbPositionKeyData;
  279.  
  280.  
  281.     if (pQuaternionKeyDataObject)
  282.         pQuaternionKeyDataObject->Release();
  283.  
  284.     if (pScaleKeyDataObject)
  285.         pScaleKeyDataObject->Release();
  286.  
  287.     if (pPositionKeyDataObject)
  288.         pPositionKeyDataObject->Release();
  289.  
  290.     if (pAnimDataObject)
  291.         pAnimDataObject->Release();
  292.  
  293.     return hr;
  294. }
  295.  
  296.  
  297.  
  298.  
  299.  
  300.  
  301.  
  302.  
  303.  
  304.  
  305.  
  306.  
  307.  
  308. HRESULT    LoadPolyMesh
  309.         (
  310.             MDagPath&    mdpTransform, 
  311.             MDagPath&    mdpMesh,
  312.             SMesh*        pShape
  313.         ) 
  314. {
  315.     HRESULT    hr = S_OK;
  316.     MStatus    stat = MStatus::kSuccess;
  317.  
  318.  
  319.     UINT iVert, iRep, iNorm, iUV, iGroup, iFace, iIndex, iBone, iBoneRemap;
  320.     UINT cRepsMax, cBonesMax = 1;
  321.     UINT iInstance;
  322.  
  323.     MFnMesh fnMesh;
  324.  
  325.     MMatrix    mmWorldTransform;
  326.  
  327.     // geometry info
  328.     MFloatPointArray mfpaPoints;
  329.     MFloatVectorArray mfvaNormals;
  330.     MFloatArray mfaUs, mfaVs;
  331.  
  332.     // material info
  333.     MObjectArray maoShaders;
  334.     MIntArray maiPolyShaderMap;
  335.  
  336.     MItMeshPolygon itPoly(MObject::kNullObj);
  337.     MItDag itBones(MItDag::kDepthFirst, MFn::kJoint);
  338.  
  339.     // skinning info
  340.     MItDependencyNodes itClusters;
  341.     MFnSkinCluster fnSkin;
  342.     MTransformationMatrix* amtmBonePositions = NULL;
  343.     MFnWeightGeometryFilter fnCluster;
  344.     bool** aabBonePointTable = NULL;    // (aabBonePointTable[i][j] == true) iff bone i influences point j
  345.     UINT* acBonesPerPoint = NULL;        // acBonesPerPoint[j] = num bones that influence point j (used for smooth skinning)
  346.     MObjectArray maoBones, maoWorldBindMatrices, maoLocalBindMatrices;
  347.     MIntArray maiBoneRemap;
  348.     // the following are used per bone
  349.     MFnTransform fnBone;
  350.     MObject moComponents, moWorldBindMatrix, moLocalBindMatrix;
  351.     MPlug mpToBindPose;
  352.     MFnMatrixData fnMatrix;
  353.     char* szBone = NULL;
  354.     char* pcBone;
  355.     float* afWeights = NULL;
  356.     UINT* aiPoints = NULL;
  357.     bool* abBonePointArray = NULL;
  358.     UINT cWeights;
  359.     UINT iBoneIdx, iWeight;
  360.     bool bSmoothSkinning, bRigidSkinning, bUnkownSkinning;
  361.     bool bVisibility, bLodVisibility, bOverrideEnabled, bOverrideVisibility;
  362.  
  363.     // initialize mesh
  364.     pShape->m_kType = SMesh::UNKNOWN;
  365.     pShape->m_nGroups = 0;
  366.     pShape->m_aGroups = NULL;
  367.     pShape->m_nPoints = 0;
  368.     pShape->m_aPoints = NULL;
  369.     pShape->m_nVertexColors = 0;
  370.     pShape->m_aVertexColors = NULL;
  371.     pShape->m_nNormals = 0;
  372.     pShape->m_aNormals = NULL;
  373.     pShape->m_nUVs = 0;
  374.     pShape->m_aUVs = NULL;
  375.     pShape->m_nReps = 0;
  376.     pShape->m_aReps = NULL;
  377.     pShape->m_nFaces = 0;
  378.     pShape->m_aFaces = NULL;
  379.     pShape->m_nFaceIndices = 0;
  380.     pShape->m_nBones = 0;
  381.     pShape->m_aBones = NULL;
  382.     pShape->m_nMaxBonesPerFace   = 0;
  383.     pShape->m_nMaxBonesPerPoint = 0;
  384.     
  385.  
  386.  
  387.     mmWorldTransform = mdpTransform.inclusiveMatrix();    // load the mesh's world transform (needed if skinning info is found)    
  388.  
  389.     if (!mdpMesh.hasFn(MFn::kMesh))
  390.     {
  391.         cout << "LoadPolyMesh(): Input path was not a mesh as expected.  Aborting..." << endl;
  392.         goto e_Exit;
  393.     }
  394.  
  395.     stat = fnMesh.setObject(mdpMesh);
  396.     if (!stat)
  397.     {
  398.         cout << "LoadPolyMesh(): Aborting because object could not be read as mesh." << endl;
  399.         goto e_Exit;
  400.     }
  401.  
  402.     // check if mesh is visible
  403.     bVisibility = true;
  404.     bLodVisibility = true;
  405.     bOverrideEnabled = false;
  406.     bOverrideVisibility = true;
  407.  
  408.     do    // ONCE
  409.     {
  410.         MPlug mpVisibility, mpLodVisibility, mpOverrideEnabled, mpOverrideVisibility;
  411.  
  412.         mpVisibility = fnMesh.findPlug("visibility", &stat);
  413.         if (!stat)
  414.             break;
  415.  
  416.         stat = mpVisibility.getValue(bVisibility);
  417.         if (!stat)
  418.             break;
  419.  
  420.         mpLodVisibility = fnMesh.findPlug("lodVisibility", &stat);
  421.         if (!stat)
  422.             break;
  423.  
  424.         stat = mpLodVisibility.getValue(bLodVisibility);
  425.         if (!stat)
  426.             break;
  427.  
  428.         mpOverrideEnabled = fnMesh.findPlug("overrideEnabled", &stat);
  429.         if (!stat)
  430.             break;
  431.  
  432.         stat = mpOverrideEnabled.getValue(bOverrideEnabled);
  433.         if (!stat)
  434.             break;
  435.  
  436.         mpOverrideVisibility = fnMesh.findPlug("overrideVisibility", &stat);
  437.         if (!stat)
  438.             break;
  439.  
  440.         stat = mpOverrideVisibility.getValue(bOverrideVisibility);
  441.         if (!stat)
  442.             break;
  443.     }
  444.     while (false);
  445.  
  446.     // if mesh is not visible then skip it
  447.     if (!(bVisibility && bLodVisibility && (!bOverrideEnabled || bOverrideVisibility)))
  448.     {
  449.         cout << "Skipping mesh \"" << fnMesh.name().asChar() << "\" because it is invisible..." << endl;
  450.         goto e_Exit;
  451.     }
  452.         
  453.     cout << "\t\tLoading mesh \"" << fnMesh.name().asChar() << "\"..." << endl;
  454.  
  455.     // get instance number of mesh (if mesh is uninstanced then default is 0)
  456.     iInstance = 0;
  457.     if (mdpMesh.isInstanced()) 
  458.     {
  459.         iInstance = mdpMesh.instanceNumber();
  460.         cout << "LoadPolyMesh(): This mesh, \"" << mdpMesh.fullPathName() << "\" is instanced (instance num " << iInstance << "); instanced meshes haven't been tested yet." << endl;
  461.     }
  462.  
  463.  
  464.     pShape->m_nPoints = (UINT)fnMesh.numVertices();    // point count
  465.     if (pShape->m_nPoints > 0)
  466.     {
  467.         pShape->m_aPoints = new DtVec3f[pShape->m_nPoints];
  468.         if (pShape->m_aPoints == NULL)
  469.         {
  470.             hr = E_OUTOFMEMORY;
  471.             cout << "LoadPolyMesh(): Could not allocate memory for vertices." << endl;
  472.             goto e_Exit;
  473.         }
  474.     }
  475.     else
  476.     {
  477.         cout << "LoadPolyMesh(): Aborting because no vertices were found." << endl;
  478.         goto e_Exit;
  479.     }
  480.  
  481.     pShape->m_nNormals = (UINT)fnMesh.numNormals();        // normal count
  482.     if (pShape->m_nNormals > 0)
  483.     {
  484.         pShape->m_aNormals = new DtVec3f[pShape->m_nNormals];
  485.         if (NULL == pShape->m_aNormals)
  486.         {
  487.             hr = E_OUTOFMEMORY;
  488.             cout << "LoadPolyMesh(): Could not allocate memory for normals." << endl;
  489.             goto e_Exit;
  490.         }
  491.     }
  492.  
  493.     pShape->m_nUVs = (UINT)fnMesh.numUVs();            // uv count
  494.     if (pShape->m_nUVs > 0)
  495.     {
  496.         pShape->m_aUVs = new DtVec2f[pShape->m_nUVs];
  497.         if (NULL == pShape->m_aUVs)
  498.         {
  499.             hr = E_OUTOFMEMORY;
  500.             cout << "LoadPolyMesh(): Could not allocate memory for tex-coords." << endl;
  501.             goto e_Exit;
  502.         }
  503.     }
  504.  
  505.  
  506.  
  507.     // MATERIALS
  508.     stat = fnMesh.getConnectedShaders(iInstance, maoShaders, maiPolyShaderMap);
  509.     if (!stat)
  510.     {
  511.         cout << "LoadPolyMesh(): Aborting because shaders could not be found." << endl;
  512.         goto e_Exit;
  513.     }
  514.  
  515.     pShape->m_nGroups = maoShaders.length();
  516.  
  517.     if (pShape->m_nGroups == 0)
  518.         goto e_ExitMaterials;
  519.     
  520.     pShape->m_aGroups = new SGroup[pShape->m_nGroups];
  521.     if (pShape->m_aGroups == NULL) 
  522.     {
  523.         hr = E_OUTOFMEMORY;
  524.         cout << "LoadPolyMesh(): Could not allocate memory for materials." << endl;
  525.         goto e_Exit;
  526.     }
  527.  
  528.     for (iGroup = 0; iGroup < pShape->m_nGroups; iGroup++)
  529.     {
  530.         // load default values into group
  531.         pShape->m_aGroups[iGroup].m_fDiffuseRed   = 1.0f;
  532.         pShape->m_aGroups[iGroup].m_fDiffuseGreen = 1.0f;
  533.         pShape->m_aGroups[iGroup].m_fDiffuseBlue  = 1.0f;
  534.  
  535.         pShape->m_aGroups[iGroup].m_fEmissiveRed   = 0.0f;
  536.         pShape->m_aGroups[iGroup].m_fEmissiveGreen = 0.0f;
  537.         pShape->m_aGroups[iGroup].m_fEmissiveBlue  = 0.0f;
  538.  
  539.         pShape->m_aGroups[iGroup].m_fSpecularRed   = 1.0f;
  540.         pShape->m_aGroups[iGroup].m_fSpecularGreen = 1.0f;
  541.         pShape->m_aGroups[iGroup].m_fSpecularBlue  = 1.0f;
  542.  
  543.         pShape->m_aGroups[iGroup].m_fTransparency = 0.0f;
  544.         pShape->m_aGroups[iGroup].m_fShininess    = 1.0f;
  545.  
  546.         pShape->m_aGroups[iGroup].m_szName = NULL;
  547.         pShape->m_aGroups[iGroup].m_szTextureFile = NULL;
  548.  
  549.         MPlug mpShader = MFnDependencyNode(maoShaders[iGroup]).findPlug("surfaceShader", &stat);
  550.         if (!stat || mpShader.isNull())
  551.         {
  552.             cout << "WARNING: Using default material because shader was not a surfaceShader." << endl;
  553.             continue;
  554.         }
  555.         else
  556.         {
  557.             MPlugArray aPlugs;
  558.             MFnDependencyNode fnShaderNode;
  559.  
  560.             stat = fnShaderNode.setObject(mpShader.node());
  561.             if (stat)    // on success
  562.             {
  563.                 // get material name
  564.                 pShape->m_aGroups[iGroup].m_szName = new char[1 + fnShaderNode.name().length()];
  565.                 if (NULL == pShape->m_aGroups[iGroup].m_szName) 
  566.                 {
  567.                     hr = E_OUTOFMEMORY;
  568.                     cout << "LoadPolyMesh(): Could not allocate material name." << endl;
  569.                     goto e_Exit;
  570.                 }
  571.  
  572.                 strcpy(pShape->m_aGroups[iGroup].m_szName, fnShaderNode.name().asChar());
  573.  
  574.                 for (pcBone = pShape->m_aGroups[iGroup].m_szName; *pcBone != '\0'; pcBone++)    
  575.                 {    // replace '|' and ' ' characters by '_' in the maya partial pathname
  576.                     if (*pcBone == ' ' || *pcBone == '|')
  577.                         *pcBone = '_';
  578.                 }
  579.  
  580.                 g_Arrays.Add(STRING, pShape->m_aGroups[iGroup].m_szName);
  581.             }
  582.  
  583.  
  584.             mpShader.connectedTo(aPlugs, true, false, &stat);
  585.             if (!stat || aPlugs.length() != 1)
  586.             {
  587.                 cout << "WARNING: Using default material because there was an error getting the shader." << endl;
  588.                 continue;
  589.             }
  590.             
  591.             // default values
  592.             MColor mcDiffuse(pShape->m_aGroups[iGroup].m_fDiffuseRed, pShape->m_aGroups[iGroup].m_fDiffuseGreen, pShape->m_aGroups[iGroup].m_fDiffuseBlue);
  593.             MColor mcSpecular(pShape->m_aGroups[iGroup].m_fSpecularRed, pShape->m_aGroups[iGroup].m_fSpecularGreen, pShape->m_aGroups[iGroup].m_fSpecularBlue);
  594.             MColor mcEmissive(pShape->m_aGroups[iGroup].m_fEmissiveRed, pShape->m_aGroups[iGroup].m_fEmissiveGreen, pShape->m_aGroups[iGroup].m_fEmissiveBlue);
  595.             MColor mcTransparency(pShape->m_aGroups[iGroup].m_fTransparency, pShape->m_aGroups[iGroup].m_fTransparency, pShape->m_aGroups[iGroup].m_fTransparency);
  596.             float fDiffuseCoeff = 1.0f;
  597.  
  598.             switch (aPlugs[0].node().apiType())
  599.             { 
  600.                 case MFn::kLambert:
  601.                 {            
  602.                     MFnLambertShader fnShader(aPlugs[0].node(), &stat);
  603.                     if (!stat)
  604.                         break;
  605.  
  606.                     fDiffuseCoeff = fnShader.diffuseCoeff();
  607.  
  608.                     mcDiffuse  = fnShader.color() * fDiffuseCoeff;
  609.                     mcEmissive = fnShader.incandescence() * fnShader.glowIntensity();
  610.                     mcSpecular = mcDiffuse;    // set specular color to the diffuse color
  611.             
  612.                     mcTransparency = fnShader.transparency();
  613.  
  614.                     pShape->m_aGroups[iGroup].m_fShininess = 0.0f;
  615.  
  616.                     break;
  617.                 }
  618.                 case MFn::kBlinn:
  619.                 {
  620.                     MFnBlinnShader fnShader(aPlugs[0].node(), &stat);
  621.                     if (!stat)
  622.                         break;
  623.  
  624.                     fDiffuseCoeff = fnShader.diffuseCoeff();
  625.  
  626.                     mcDiffuse  = fnShader.color() * fDiffuseCoeff;
  627.                     mcEmissive = fnShader.incandescence() * fnShader.glowIntensity();
  628.                     mcSpecular = fnShader.specularColor();
  629.  
  630.                     mcTransparency = fnShader.transparency();
  631.                     
  632.                     pShape->m_aGroups[iGroup].m_fShininess = fnShader.reflectivity();        // TODO:  I'm not at all sure about this...
  633.  
  634.                     break;
  635.                 }
  636.                 case MFn::kPhong:
  637.                 {
  638.                     MFnPhongShader fnShader(aPlugs[0].node(), &stat);
  639.                     if (!stat)
  640.                         break;
  641.  
  642.                     fDiffuseCoeff = fnShader.diffuseCoeff();
  643.  
  644.                     mcDiffuse  = fnShader.color() * fDiffuseCoeff;
  645.                     mcEmissive = fnShader.incandescence() * fnShader.glowIntensity();
  646.                     mcSpecular = fnShader.specularColor();
  647.             
  648.                     mcTransparency = fnShader.transparency();
  649.  
  650.                     pShape->m_aGroups[iGroup].m_fShininess = fnShader.reflectivity();        // TODO:  I'm not at all sure about this...
  651.  
  652.                     break;    
  653.                 }
  654.                 default:
  655.                 {
  656.                     MFnDependencyNode fnNode(aPlugs[0].node(), &stat);
  657.                     if (!stat) 
  658.                         break;
  659.  
  660.                     MPlug mpDiffuse = fnNode.findPlug("outColor");
  661.                     if (stat && mpDiffuse.numElements() >= 3) 
  662.                     {
  663.                         mpDiffuse[0].getValue(mcDiffuse.r);
  664.                         mpDiffuse[1].getValue(mcDiffuse.g);
  665.                         mpDiffuse[2].getValue(mcDiffuse.b);
  666.  
  667.                         mcSpecular = mcDiffuse;
  668.                     }
  669.  
  670.                     MPlug mpEmissive = fnNode.findPlug("outGlowColor", &stat);
  671.                     if (stat && mpEmissive.numElements() >= 3) 
  672.                     {
  673.                         mpEmissive[0].getValue(mcDiffuse.r);
  674.                         mpEmissive[1].getValue(mcDiffuse.g);
  675.                         mpEmissive[2].getValue(mcDiffuse.b);
  676.                     }
  677.  
  678.                     MPlug mpTransparency = fnNode.findPlug("outTransparency", &stat);
  679.                     if (stat && mpTransparency.numElements() >= 3) 
  680.                     {
  681.                         mpTransparency[0].getValue(mcDiffuse.r);
  682.                         mpTransparency[1].getValue(mcDiffuse.g);
  683.                         mpTransparency[2].getValue(mcDiffuse.b);
  684.                     }
  685.  
  686.                     break;
  687.                 }
  688.             }
  689.             
  690.             pShape->m_aGroups[iGroup].m_fDiffuseRed   = mcDiffuse.r;
  691.             pShape->m_aGroups[iGroup].m_fDiffuseGreen = mcDiffuse.g;
  692.             pShape->m_aGroups[iGroup].m_fDiffuseBlue  = mcDiffuse.b;
  693.  
  694.             pShape->m_aGroups[iGroup].m_fSpecularRed   = mcSpecular.r;
  695.             pShape->m_aGroups[iGroup].m_fSpecularGreen = mcSpecular.g;
  696.             pShape->m_aGroups[iGroup].m_fSpecularBlue  = mcSpecular.b;
  697.  
  698.             pShape->m_aGroups[iGroup].m_fEmissiveRed   = mcEmissive.r;
  699.             pShape->m_aGroups[iGroup].m_fEmissiveGreen = mcEmissive.g;
  700.             pShape->m_aGroups[iGroup].m_fEmissiveBlue  = mcEmissive.b;
  701.  
  702.             // TODO:  not sure if this is the best way to get transparency
  703.             // take root mean square of the components of mcolTransparency
  704.             mcTransparency *= mcTransparency;
  705.             pShape->m_aGroups[iGroup].m_fTransparency = (float)sqrt((mcTransparency.r + mcTransparency.g + mcTransparency.b) / 3);
  706.  
  707.  
  708.             // find texture file info if available
  709.             MPlug mpColor = MFnDependencyNode(aPlugs[0].node()).findPlug("color", &stat);
  710.             if (!stat)
  711.                 continue;
  712.  
  713.             MItDependencyGraph dgIt(mpColor, MFn::kFileTexture, MItDependencyGraph::kUpstream, MItDependencyGraph::kBreadthFirst, MItDependencyGraph::kNodeLevel, &stat);
  714.             if (!stat)
  715.                 continue;
  716.             
  717.             dgIt.disablePruningOnFilter();
  718.  
  719.             if (dgIt.isDone())
  720.                 continue;    // no texture file node was found, so just continue.
  721.               
  722.             // get the texture file name
  723.             MString msTextureFile;
  724.             MFnDependencyNode(dgIt.thisNode()).findPlug("fileTextureName").getValue(msTextureFile);
  725.  
  726.             pShape->m_aGroups[iGroup].m_szTextureFile = NULL;
  727.  
  728.             if (g_bRelativeTexFile)
  729.             {    // use a trick to get the relative file name without too much hassle
  730.                 MFileObject mFile;
  731.  
  732.                 mFile.setFullName(msTextureFile);
  733.  
  734.                 pShape->m_aGroups[iGroup].m_szTextureFile = new char[mFile.name().length() + 1];
  735.                 if (pShape->m_aGroups[iGroup].m_szTextureFile == NULL)
  736.                 {
  737.                     hr = E_OUTOFMEMORY;
  738.                     cout << "LoadPolyMesh(): Not enough memory for texture file name." << endl;
  739.                     goto e_Exit;
  740.                 }
  741.  
  742.                 strcpy(pShape->m_aGroups[iGroup].m_szTextureFile, mFile.name().asChar());
  743.             }
  744.             else
  745.             {    // directly use the texture file name
  746.                 pShape->m_aGroups[iGroup].m_szTextureFile = new char[msTextureFile.length() + 1];
  747.                 if (pShape->m_aGroups[iGroup].m_szTextureFile == NULL)
  748.                 {
  749.                     hr = E_OUTOFMEMORY;
  750.                     cout << "LoadPolyMesh(): Not enough memory for texture file name." << endl;
  751.                     goto e_Exit;
  752.                 }
  753.  
  754.                 strcpy(pShape->m_aGroups[iGroup].m_szTextureFile, msTextureFile.asChar());
  755.             }
  756.  
  757.             g_Arrays.Add(STRING, pShape->m_aGroups[iGroup].m_szTextureFile);
  758.  
  759.             // TODO: in case of texture, use diffuse coeff as diffuse color
  760.             pShape->m_aGroups[iGroup].m_fDiffuseRed   = fDiffuseCoeff;
  761.             pShape->m_aGroups[iGroup].m_fDiffuseGreen = fDiffuseCoeff;
  762.             pShape->m_aGroups[iGroup].m_fDiffuseBlue  = fDiffuseCoeff;
  763.         }
  764.     }
  765.  
  766. e_ExitMaterials:
  767.  
  768.  
  769.     // FACES & REPS
  770.  
  771.     // initialize reps
  772.     pShape->m_nReps = pShape->m_nPoints;
  773.     cRepsMax = pShape->m_nReps;        // NOTE: cRepsMax > 0 (because earlier we returned if m_nPoints == 0)
  774.  
  775.     pShape->m_aReps = NULL;
  776.     pShape->m_aReps = new SRep[cRepsMax];
  777.     if (pShape->m_aReps == NULL)
  778.     {
  779.         hr = E_OUTOFMEMORY;
  780.         cout << "LoadPolyMesh(): Could not allocate memory for point reps." << endl;
  781.         goto e_Exit;
  782.     }
  783.     
  784.     for (iRep = 0; iRep < pShape->m_nReps; iRep++) 
  785.     {
  786.         pShape->m_aReps[iRep].m_iUV   = (UINT)(-1);        // signifies "unvisited"
  787.         pShape->m_aReps[iRep].m_iNorm = (UINT)(-1);        // signifies "unvisited"
  788.  
  789.         pShape->m_aReps[iRep].m_iNext  = iRep;
  790.         pShape->m_aReps[iRep].m_iFirst    = iRep;
  791.  
  792.         pShape->m_aReps[iRep].m_nReps  = 0;
  793.     }
  794.  
  795.     // load faces
  796.  
  797.     pShape->m_nFaces = (UINT)fnMesh.numPolygons();
  798.  
  799.     if (pShape->m_nFaces == 0)
  800.     {
  801.         cout << "WARNING: Aborting because mesh contains no faces." << endl;
  802.         goto e_Exit;
  803.     }
  804.  
  805.     if (pShape->m_nGroups > 0 && maiPolyShaderMap.length() != pShape->m_nFaces)
  806.     {
  807.         cout << "WARNING: Aborting because polygon/shader map length is not equal to number of faces." << endl;
  808.         goto e_Exit;
  809.     }
  810.  
  811.     pShape->m_aFaces = new SFace[pShape->m_nFaces];
  812.     if (pShape->m_aFaces == NULL)
  813.     {
  814.         hr = E_OUTOFMEMORY;
  815.         cout << "LoadPolyMesh(): Could not allocate memory for faces." << endl;
  816.         goto e_Exit;
  817.     }
  818.  
  819.     pShape->m_nFaceIndices = 0;
  820.  
  821.     stat = itPoly.reset(fnMesh.object());
  822.     if (!stat)
  823.     {
  824.         cout << "WARNING: Aborting because polygon iterator could not be initialized." << endl;
  825.         goto e_Exit;
  826.     }
  827.  
  828.     for (iFace = 0; !itPoly.isDone(); iFace++, itPoly.next())
  829.     {
  830.         if (pShape->m_nGroups > 0)
  831.             pShape->m_aFaces[iFace].m_iGroup = maiPolyShaderMap[iFace];
  832.         else
  833.             pShape->m_aFaces[iFace].m_iGroup = (UINT)(-1);
  834.  
  835.         if (itPoly.polygonVertexCount() == 0)
  836.             goto e_Exit;
  837.  
  838.         pShape->m_aFaces[iFace].m_nIndices = itPoly.polygonVertexCount();
  839.         
  840.         pShape->m_aFaces[iFace].m_aIndices = NULL;
  841.         pShape->m_aFaces[iFace].m_aIndices = new UINT[pShape->m_aFaces[iFace].m_nIndices];
  842.         if (pShape->m_aFaces[iFace].m_aIndices == NULL)
  843.         {
  844.             hr = E_OUTOFMEMORY;
  845.             cout << "LoadPolyMesh(): Could not allocate memory for face " << iFace << "'s indices." << endl;
  846.             goto e_Exit;
  847.         }
  848.  
  849.         for (iIndex = 0; iIndex < pShape->m_aFaces[iFace].m_nIndices; iIndex++)
  850.         {
  851.             int iUV;
  852.             bool bFound = false;
  853.  
  854.             iVert = itPoly.vertexIndex(iIndex, &stat);
  855.             if (!stat)
  856.             {
  857.                 hr = E_FAIL;
  858.                 cout << "LoadPolyMesh(): Could not load face " << iFace << "'s vertex number " << iVert << endl;
  859.                 goto e_Exit;
  860.             }
  861.  
  862.             if (pShape->m_nNormals > 0)
  863.             {
  864.                 iNorm = itPoly.normalIndex(iIndex, &stat);
  865.                 if (!stat)
  866.                 {
  867.                     iNorm = (UINT)(-1);
  868.                     cout << "WARNING: Using default normal because there was an error in retrieving it." << endl;
  869.                 }
  870.             }
  871.             else
  872.             {
  873.                 iNorm = (UINT)(-1);
  874.             }
  875.  
  876.             if (pShape->m_nUVs > 0)
  877.             {
  878.                 stat = itPoly.getUVIndex(iIndex, iUV);
  879.                 if (!stat)
  880.                 {
  881.                     iUV = (UINT)(-1);
  882.                     cout << "WARNING: Using default UV because there was an error in retrieving it." << endl;
  883.                 }
  884.             }
  885.             else
  886.             {
  887.                 iUV = (UINT)(-1);
  888.             }
  889.  
  890.  
  891.             if (pShape->m_aReps[iVert].m_nReps == 0)     
  892.             {    // first time through this rep
  893.                 pShape->m_aReps[iVert].m_iUV   = (UINT)iUV;    
  894.                 pShape->m_aReps[iVert].m_iNorm = iNorm;
  895.  
  896.                 pShape->m_aReps[iVert].m_nReps = 1;
  897.  
  898.                 pShape->m_aFaces[iFace].m_aIndices[iIndex] = iVert;    // update face indices
  899.             }
  900.             else
  901.             {
  902.                 UINT iPrevRep;
  903.  
  904.                 iRep = iVert;
  905.                 do 
  906.                 {
  907.                     if ((UINT)iUV == pShape->m_aReps[iRep].m_iUV && iNorm == pShape->m_aReps[iRep].m_iNorm)
  908.                     {
  909.                         bFound = true;
  910.                         pShape->m_aFaces[iFace].m_aIndices[iIndex] = iRep;    // update face indices
  911.                     }
  912.  
  913.                     iPrevRep = iRep;
  914.                     iRep     = pShape->m_aReps[iRep].m_iNext;
  915.                 } while (!bFound && iRep != pShape->m_aReps[iRep].m_iFirst);
  916.  
  917.  
  918.                 if (!bFound) 
  919.                 {    // NOTE: iRep == iVert == pShape->m_aReps[iRep].m_iFirst  (HINT: see the condition in the do..while loop above)
  920.                     // append new rep 
  921.                     if (pShape->m_nReps >= cRepsMax) 
  922.                     {    // double array size
  923.                         cRepsMax += cRepsMax;
  924.  
  925.                         SRep* rgNewReps;
  926.                         
  927.                         rgNewReps = NULL;
  928.                         rgNewReps = new SRep[cRepsMax];
  929.                         if (rgNewReps == NULL)
  930.                         {
  931.                             hr = E_OUTOFMEMORY;
  932.                             cout << "LoadPolyMesh(): Could not allocate memory for new rep array." << endl;
  933.                             goto e_Exit;
  934.                         }
  935.  
  936.                         memcpy(rgNewReps, pShape->m_aReps, pShape->m_nReps * sizeof(SRep));
  937.  
  938.                         delete[] pShape->m_aReps;
  939.  
  940.                         pShape->m_aReps = rgNewReps;
  941.                     }
  942.  
  943.                     // create a new rep at the end of the array
  944.                     pShape->m_aReps[pShape->m_nReps].m_iUV   = iUV;
  945.                     pShape->m_aReps[pShape->m_nReps].m_iNorm = iNorm;
  946.  
  947.                     pShape->m_aReps[pShape->m_nReps].m_iFirst = iRep;    
  948.                     pShape->m_aReps[pShape->m_nReps].m_iNext  = iRep;        // link the new rep to the first rep
  949.  
  950.                     pShape->m_aReps[iPrevRep].m_iNext = pShape->m_nReps;    // link the last rep to the new rep
  951.  
  952.                     pShape->m_aReps[iRep].m_nReps++;    // increment the rep count at the first rep
  953.  
  954.                     pShape->m_aFaces[iFace].m_aIndices[iIndex] = pShape->m_nReps;    // update face indices
  955.  
  956.                     pShape->m_nReps++;    // increment the total rep count
  957.                 } // if !bFound
  958.             }
  959.  
  960.         } // for loop through indices
  961.  
  962.  
  963.         pShape->m_nFaceIndices += pShape->m_aFaces[iFace].m_nIndices;
  964.  
  965.     } // for loop through faces
  966.  
  967.     if ((UINT)fnMesh.numPolygons() != iFace)
  968.     {
  969.         cout << "WARNING: Aborting because of mismatch in face count." << endl;
  970.         goto e_Exit;
  971.     }
  972.  
  973.  
  974.     // SKINNING
  975.  
  976.     acBonesPerPoint = new UINT[pShape->m_nPoints];
  977.     if (acBonesPerPoint == NULL)
  978.     {
  979.         hr = E_OUTOFMEMORY;
  980.         cout << "LoadPolyMesh(): Could not allocate memory for bones-per-point counts." << endl;
  981.         goto e_Exit;
  982.     }
  983.  
  984.     memset(acBonesPerPoint, 0, pShape->m_nPoints * sizeof(UINT));    // zero out the bone counts
  985.  
  986.     pShape->m_aBones = new SBone[cBonesMax];    // NOTE: cBonesMax is initialized to 10
  987.     if (pShape->m_aBones == NULL)
  988.     {
  989.         hr = E_OUTOFMEMORY;
  990.         cout << "LoadPolyMesh(): Could not allocate memory for bones." << endl;
  991.         goto e_Exit;
  992.     }
  993.  
  994.     aabBonePointTable = new bool*[cBonesMax];
  995.     if (aabBonePointTable == NULL)
  996.     {
  997.         hr = E_OUTOFMEMORY;
  998.         cout << "LoadPolyMesh(): Could not allocate memory for point/bone table." << endl;
  999.         goto e_Exit;
  1000.     }
  1001.  
  1002.     memset(aabBonePointTable, 0, cBonesMax * sizeof(bool*));    // NULLify the array
  1003.  
  1004.  
  1005.  
  1006.     // SMOOTH SKINNING
  1007.  
  1008.     stat = itClusters.reset(MFn::kSkinClusterFilter);
  1009.     if (!stat)
  1010.     {
  1011.         cout << "WARNING: Could not search skin clusters." << endl;
  1012.         goto e_ExitSmoothSkinning;
  1013.     }
  1014.  
  1015.     for (bSmoothSkinning = false; !itClusters.isDone(); itClusters.next()) 
  1016.     {
  1017.         MDagPathArray dagBonePaths;
  1018.  
  1019.         stat = fnSkin.setObject(itClusters.item());
  1020.         if (!stat)
  1021.         {
  1022.             cout << "WARNING: Ignoring this skin cluster because couldn't read the object." << endl;
  1023.             continue;
  1024.         }
  1025.  
  1026.         fnSkin.indexForOutputShape(fnMesh.object(), &stat);
  1027.         if (!stat)
  1028.             continue;    // our mesh is not an output shape for this skin cluster so skip this cluster
  1029.  
  1030.         if (!bSmoothSkinning)
  1031.         {
  1032.             cout << "\t\t\tSmooth skinning:";
  1033.             bSmoothSkinning = true;
  1034.         }
  1035.  
  1036.         // bone DAG paths
  1037.         fnSkin.influenceObjects(dagBonePaths, &stat);
  1038.         if (!stat)
  1039.         {
  1040.             cout << "WARNING: Ignoring this skin cluster because could not get influence objects." << endl;
  1041.             continue;
  1042.         }
  1043.  
  1044.         for (iBone = 0; iBone < dagBonePaths.length(); iBone++)
  1045.         {
  1046.             MFloatArray Weights;
  1047.             MSelectionList SelectionList;
  1048.             MDagPath dagPath;
  1049.  
  1050.             cout << " " << dagBonePaths[iBone].partialPathName();
  1051.  
  1052.             // load affected points & weights
  1053.             stat = fnSkin.getPointsAffectedByInfluence(dagBonePaths[iBone], SelectionList, Weights);
  1054.             if (!stat)
  1055.             {
  1056.                 cout << "WARNING: Ignoring bone because skin weights could not be obtained." << endl;
  1057.                 continue;
  1058.             }
  1059.  
  1060.             cWeights = Weights.length();
  1061.             if (0 == cWeights)
  1062.                 continue;    // no influences so ignore this bone
  1063.  
  1064.             if (1 != SelectionList.length())
  1065.             {    // unexpected selection list size
  1066.                 cout << "WARNING: Ignoring bone because length of selection list is not 1." << endl;
  1067.                 continue;
  1068.             }
  1069.  
  1070.             stat = SelectionList.getDagPath(0, dagPath, moComponents);
  1071.             if (!stat)
  1072.             {
  1073.                 cout << "WARNING: Ignoring bone because could not read DAG path from selection list." << endl;
  1074.                 continue;
  1075.             }
  1076.  
  1077.             if (!(dagPath == mdpMesh))
  1078.             {    // bone does not influence this mesh
  1079.                 cout << "WARNING: Ignoring bone because unexpected affected mesh encountered." << endl;
  1080.                 continue;
  1081.             }
  1082.  
  1083.  
  1084.             if (!dagBonePaths[iBone].hasFn(MFn::kTransform))
  1085.             {
  1086.                 cout << "WARNING: Ignoring bone because it is not a transform." << endl;
  1087.                 continue;
  1088.             }
  1089.             
  1090.             stat = fnBone.setObject(dagBonePaths[iBone]);
  1091.             if (!stat)
  1092.             {
  1093.                 cout << "WARNING: Ignoring bone because could not create function set." << endl;
  1094.                 continue;
  1095.             }
  1096.  
  1097.             // BIND POSE
  1098.             moWorldBindMatrix = MObject::kNullObj;
  1099.             moLocalBindMatrix = MObject::kNullObj;
  1100.  
  1101.             mpToBindPose = fnBone.findPlug("bindPose", &stat);
  1102.             if (stat) // success
  1103.             {
  1104.                 stat = mpToBindPose.getValue(moWorldBindMatrix);
  1105.                 if (!stat)
  1106.                 {
  1107.                     cout << "WARNING: Ignoring bone. (Could not get 'bindPose' plug value.)" << endl;
  1108.                     continue;
  1109.                 }
  1110.             }
  1111.             else // failure
  1112.             {
  1113.                 mpToBindPose = fnBone.findPlug("message", &stat);
  1114.                 if (!stat)
  1115.                 {
  1116.                     cout << "WARNING: Ignoring bone. (Could not find 'message' plug.)" << endl;
  1117.                     continue;
  1118.                 }
  1119.             }
  1120.  
  1121.             // attempt to read local transform (preferable), and possibly world transform (if it wasn't read before)
  1122.             do
  1123.             {
  1124.                 MPlug mpDagPose;
  1125.                 MFnDependencyNode fnDagPose;
  1126.                 MPlugArray mapConnections;
  1127.                 MObject moAttribWM, moAttribXM;
  1128.  
  1129.                 mpToBindPose.connectedTo(mapConnections, false, true, &stat);
  1130.                 if (!stat)
  1131.                     break;
  1132.  
  1133.                 if (mapConnections.length() == 0)
  1134.                 {
  1135.                     stat = MS::kFailure;
  1136.                     break;
  1137.                 }
  1138.  
  1139.                 mpDagPose = mapConnections[0];    // TODO: search through all connections instead of simply picking the first one.
  1140.  
  1141.                 stat = fnDagPose.setObject(mpDagPose.node());
  1142.                 if (!stat)
  1143.                     break;
  1144.  
  1145.                 // world bind pose matrix (overwrites moWorldBindMatrix if read previously)
  1146.                 while (moWorldBindMatrix.isNull())
  1147.                 {
  1148.                     moAttribWM = fnDagPose.attribute("worldMatrix", &stat);
  1149.                     if (!stat)
  1150.                         break;
  1151.  
  1152.                     MPlug mpWorldMatrix(mpDagPose.node(), moAttribWM);
  1153.  
  1154.                     stat = mpWorldMatrix.selectAncestorLogicalIndex(mpDagPose.logicalIndex(), moAttribWM);
  1155.                     if (!stat)
  1156.                         break;
  1157.  
  1158.                     stat = mpWorldMatrix.getValue(moWorldBindMatrix);
  1159.                     if (!stat)
  1160.                         break;
  1161.                 }
  1162.  
  1163.                 // local bind pose matrix
  1164.                 while (moLocalBindMatrix.isNull())
  1165.                 {
  1166.                     moAttribXM = fnDagPose.attribute("xformMatrix", &stat);
  1167.                     if (!stat)
  1168.                         break;
  1169.  
  1170.                     MPlug mpXformMatrix(mpDagPose.node(), moAttribXM);
  1171.  
  1172.                     stat = mpXformMatrix.selectAncestorLogicalIndex(mpDagPose.logicalIndex(), moAttribXM);
  1173.                     if (!stat)
  1174.                         break;
  1175.  
  1176.                     stat = mpXformMatrix.getValue(moLocalBindMatrix);
  1177.                     if (!stat)
  1178.                         break;
  1179.                 }
  1180.  
  1181.                 break;
  1182.             } while (false);
  1183.  
  1184.             if (moWorldBindMatrix.isNull() && moLocalBindMatrix.isNull())
  1185.             {
  1186.                 cout << "WARNING: Ignoring bone. (Neither local nor world bind matrices could be obtained.)" << endl;
  1187.                 continue;
  1188.             }
  1189.  
  1190.             
  1191.             // get bone name
  1192.             delete[] szBone;
  1193.             szBone = NULL;
  1194.             szBone = new char[1 + dagBonePaths[iBone].partialPathName().length()];
  1195.             if (NULL == szBone) 
  1196.             {
  1197.                 hr = E_OUTOFMEMORY;
  1198.                 cout << "LoadPolyMesh(): Could not allocate bone name." << endl;
  1199.                 goto e_Exit;
  1200.             }
  1201.  
  1202.             strcpy(szBone, dagBonePaths[iBone].partialPathName().asChar());
  1203.  
  1204.             for (pcBone = szBone; *pcBone != '\0'; pcBone++)    
  1205.             {    // replace '|' and ' ' characters by '_' in the maya partial pathname
  1206.                 if (*pcBone == ' ' || *pcBone == '|')
  1207.                     *pcBone = '_';
  1208.             }
  1209.  
  1210.  
  1211.             iBoneIdx = pShape->m_nBones;
  1212.  
  1213.             // add bone
  1214.             if (iBoneIdx == cBonesMax)
  1215.             {    // double array size
  1216.                 SBone* aBones = NULL;
  1217.                 bool** aabBPT = NULL;
  1218.  
  1219.                 cBonesMax *= 2;
  1220.  
  1221.                 aBones = new SBone[cBonesMax];
  1222.                 if (NULL == aBones)
  1223.                 {
  1224.                     cout << "LoadPolyMesh(): Could not allocate bones." << endl;
  1225.                     goto e_Exit;
  1226.                 }
  1227.  
  1228.                 memcpy(aBones, pShape->m_aBones, pShape->m_nBones * sizeof(SBone));
  1229.  
  1230.                 aabBPT = new bool*[cBonesMax];
  1231.                 if (NULL == aabBPT)
  1232.                 {
  1233.                     cout << "LoadPolyMesh(): Could not allocate bones." << endl;
  1234.                     goto e_Exit;
  1235.                 }
  1236.  
  1237.                 memset(aabBPT, 0, cBonesMax * sizeof(bool*));    // NULLify the table
  1238.                 memcpy(aabBPT, aabBonePointTable, pShape->m_nBones * sizeof(bool*));
  1239.  
  1240.                 delete[] pShape->m_aBones;
  1241.                 delete[] aabBonePointTable;
  1242.  
  1243.                 pShape->m_aBones = aBones;
  1244.                 aabBonePointTable = aabBPT;
  1245.             }
  1246.  
  1247.             if (iBoneIdx == pShape->m_nBones)
  1248.             {
  1249.                 aabBonePointTable[iBoneIdx] = new bool[pShape->m_nPoints];
  1250.                 if (NULL == aabBonePointTable)
  1251.                 {
  1252.                     cout << "LoadPolyMesh(): Could not allocate new column for bone point table." << endl;
  1253.                     goto e_Exit;
  1254.                 }
  1255.  
  1256.                 memset(aabBonePointTable[iBoneIdx], 0, pShape->m_nPoints * sizeof(bool));    // falsify entries
  1257.  
  1258.                 pShape->m_aBones[iBoneIdx].m_szName = szBone;
  1259.                 g_Arrays.Add(STRING, pShape->m_aBones[iBoneIdx].m_szName);
  1260.                 szBone = NULL;
  1261.  
  1262.                 maoBones.append(MObject::kNullObj);
  1263.                 maoWorldBindMatrices.append(MObject::kNullObj);
  1264.                 maoLocalBindMatrices.append(MObject::kNullObj);
  1265.  
  1266.                 pShape->m_nBones++;
  1267.             }
  1268.  
  1269.             // save object & bind position
  1270.             maoBones[iBoneIdx] = fnBone.object();
  1271.             maoWorldBindMatrices[iBoneIdx] = moWorldBindMatrix;
  1272.             maoLocalBindMatrices[iBoneIdx] = moLocalBindMatrix;
  1273.  
  1274.  
  1275.             // get the points & weights
  1276.             afWeights = NULL;
  1277.             afWeights = new float[pShape->m_aBones[iBoneIdx].m_nWeights + cWeights];
  1278.             if (NULL == afWeights)
  1279.             {
  1280.                 hr = E_OUTOFMEMORY;
  1281.                 cout << "LoadPolyMesh(): Could not allocate memory for bone weights." << endl;
  1282.                 goto e_Exit;
  1283.             }
  1284.             memcpy (afWeights, pShape->m_aBones[iBoneIdx].m_afWeights, pShape->m_aBones[iBoneIdx].m_nWeights * sizeof(float));
  1285.             delete[] pShape->m_aBones[iBoneIdx].m_afWeights;
  1286.             pShape->m_aBones[iBoneIdx].m_afWeights  = afWeights;
  1287.             afWeights = NULL;
  1288.  
  1289.             aiPoints = NULL;
  1290.             aiPoints = new UINT[pShape->m_aBones[iBoneIdx].m_nWeights + cWeights];
  1291.             if (NULL == aiPoints)
  1292.             {
  1293.                 hr = E_OUTOFMEMORY;
  1294.                 cout << "LoadPolyMesh(): Could not allocate memory for bone influenced points." << endl;
  1295.                 goto e_Exit;
  1296.             }
  1297.             memcpy (aiPoints, pShape->m_aBones[iBoneIdx].m_aiPoints, pShape->m_aBones[iBoneIdx].m_nWeights * sizeof(UINT));
  1298.             delete[] pShape->m_aBones[iBoneIdx].m_aiPoints;
  1299.             pShape->m_aBones[iBoneIdx].m_aiPoints = aiPoints;
  1300.             aiPoints = NULL;
  1301.  
  1302.             MItGeometry itPoints(dagPath, moComponents);
  1303.             if ((UINT)itPoints.count() != cWeights)
  1304.             {
  1305.                 hr = E_FAIL;
  1306.                 cout << "WARNING: Ignoring bone because number of points differed from number of weights." << endl;
  1307.                 goto e_Exit;
  1308.             }
  1309.  
  1310.             for (iWeight = 0; !itPoints.isDone(); itPoints.next(), iWeight++)
  1311.             {
  1312.                 UINT iIndex = itPoints.index();
  1313.  
  1314.                 if (iIndex >= pShape->m_nPoints)
  1315.                 {
  1316.                     cout << "WARNING: Bone affects invalid index - ignoring..." << endl;
  1317.                     continue;
  1318.                 }
  1319.  
  1320.                 if (aabBonePointTable[iBoneIdx][iIndex])
  1321.                 {
  1322.                     cout << "WARNING: Ignoring the effect of this bone on this point because the point was previously affected by this bone before." << endl;
  1323.                     continue;
  1324.                 }
  1325.  
  1326.                 pShape->m_aBones[iBoneIdx].m_aiPoints[pShape->m_aBones[iBoneIdx].m_nWeights] = iIndex;
  1327.                 pShape->m_aBones[iBoneIdx].m_afWeights[pShape->m_aBones[iBoneIdx].m_nWeights] = Weights[iWeight];
  1328.                 pShape->m_aBones[iBoneIdx].m_nWeights++;
  1329.                 pShape->m_aBones[iBoneIdx].m_nReps += pShape->m_aReps[iIndex].m_nReps;
  1330.  
  1331.                 acBonesPerPoint[iIndex]++;
  1332.                 aabBonePointTable[iBoneIdx][iIndex] = true;
  1333.  
  1334.             }    // loop through weights
  1335.  
  1336.         }    // loop through bones
  1337.  
  1338.     }    // loop through skin clusters
  1339.  
  1340.  
  1341. e_ExitSmoothSkinning:
  1342.  
  1343.     if (bSmoothSkinning)
  1344.         cout << endl;
  1345.  
  1346.  
  1347.  
  1348.     // RIGID SKINNING
  1349.  
  1350.     stat = itClusters.reset(MFn::kJointCluster);
  1351.     if (!stat)
  1352.     {
  1353.         cout << "WARNING: Could not search joint clusters." << endl;
  1354.         goto e_ExitRigidSkinning;
  1355.     }
  1356.  
  1357.     for (bRigidSkinning = false; !itClusters.isDone(); itClusters.next()) 
  1358.     {
  1359.         MFnDagNode fnDagNode;
  1360.         UINT iSet;
  1361.         MObject moJointAttrib, moDeformerSet;
  1362.         MFnDependencyNode fnNode;
  1363.         MFnSet fnSet;
  1364.         MPlugArray aPlugs;
  1365.         MSelectionList SetList;
  1366.         MDagPath dagPath;
  1367.         MFloatArray Weights;
  1368.  
  1369.         stat = fnCluster.setObject(itClusters.item());
  1370.         if (!stat)
  1371.         {
  1372.             cout << "WARNING: Ignoring this joint cluster because couldn't read the object." << endl;
  1373.             continue;
  1374.         }
  1375.  
  1376.         fnCluster.indexForOutputShape(fnMesh.object(), &stat);
  1377.         if (!stat)
  1378.             continue;    // our mesh is not an output shape for this skin cluster so skip this cluster
  1379.  
  1380.  
  1381.         // get joint
  1382.         if (!itClusters.item().hasFn(MFn::kDependencyNode))
  1383.         {
  1384.             cout << "WARNING: Ignoring joint cluster because object was not a dependency node." << endl;
  1385.             continue;
  1386.         }
  1387.  
  1388.         stat = fnNode.setObject(itClusters.item());
  1389.         if (!stat)
  1390.         {
  1391.             cout << "WARNING: Ignoring joint cluster because dependency node could not be read." << endl;
  1392.             continue;
  1393.         }
  1394.  
  1395.         moJointAttrib = fnNode.attribute("matrix", &stat);
  1396.         if (!stat)
  1397.         {
  1398.             cout << "WARNING: Ignoring joint cluster because could not get 'matrix' attribute." << endl;
  1399.             continue;
  1400.         }
  1401.  
  1402.         if (!MPlug(fnNode.object(), moJointAttrib).connectedTo(aPlugs, true, false, &stat) || !stat || aPlugs.length() != 1)
  1403.         {
  1404.             cout << "WARNING: Ignoring joint cluster because there was a problem getting connections to plug." << endl;
  1405.             continue;
  1406.         }
  1407.  
  1408.         if (aPlugs[0].node().isNull() || !aPlugs[0].node().hasFn(MFn::kTransform))
  1409.         {
  1410.             cout << "WARNING: Ignoring joint cluster because no transform attached to this cluster." << endl;
  1411.             continue;
  1412.         }
  1413.  
  1414.         stat = fnBone.setObject(aPlugs[0].node());
  1415.         if (!stat)
  1416.         {
  1417.             cout << "WARNING: Ignoring joint cluster because could not read joint object." << endl;
  1418.             continue;
  1419.         }
  1420.  
  1421.         // get deformed objects
  1422.         moDeformerSet = fnCluster.deformerSet(&stat);
  1423.         if (!stat)
  1424.         {
  1425.             cout << "WARNING: Ignoring joint cluster because could not get deformer set object." << endl;
  1426.             continue;
  1427.         }
  1428.  
  1429.         stat = fnSet.setObject(moDeformerSet);    //need the fn to get the members
  1430.         if (!stat)
  1431.         {
  1432.             cout << "WARNING: Ignoring joint cluster because could not read deformer set object." << endl;
  1433.             continue;
  1434.         }
  1435.           
  1436.  
  1437.         stat = fnSet.getMembers(SetList, true);
  1438.         if (!stat)
  1439.         {
  1440.             cout << "WARNING: Ignoring joint cluster because could not get members from set list." << endl;
  1441.             continue;
  1442.         }
  1443.  
  1444.  
  1445.         for (iSet = 0; iSet < SetList.length(); iSet++) 
  1446.         {
  1447.             stat = SetList.getDagPath(iSet, dagPath, moComponents);
  1448.             if (stat && dagPath == mdpMesh)
  1449.                 break;
  1450.         }
  1451.  
  1452.         if (iSet == SetList.length())
  1453.         {
  1454.             cout << "WARNING: Ignoring joint cluster because mesh DAG path was not found in set list." << endl;
  1455.             continue;
  1456.         }
  1457.  
  1458.         // get affected weights & points
  1459.         stat = fnCluster.getWeights(dagPath, moComponents, Weights);
  1460.         if (!stat)
  1461.         {
  1462.             cout << "WARNING: Ignoring joint cluster because could not read weights & components." << endl;
  1463.             continue;
  1464.         }
  1465.  
  1466.         cWeights = Weights.length();
  1467.         if (0 == cWeights)
  1468.             continue;
  1469.  
  1470.  
  1471.         // BIND POSE
  1472.         moWorldBindMatrix = MObject::kNullObj;
  1473.         moLocalBindMatrix = MObject::kNullObj;
  1474.  
  1475.         mpToBindPose = fnBone.findPlug("bindPose", &stat);
  1476.         if (stat) // success
  1477.         {
  1478.             stat = mpToBindPose.getValue(moWorldBindMatrix);
  1479.             if (!stat)
  1480.             {
  1481.                 cout << "WARNING: Ignoring bone. (Could not get 'bindPose' plug value.)" << endl;
  1482.                 continue;
  1483.             }
  1484.         }
  1485.         else // failure
  1486.         {
  1487.             mpToBindPose = fnBone.findPlug("message", &stat);
  1488.             if (!stat)
  1489.             {
  1490.                 cout << "WARNING: Ignoring bone. (Could not find 'message' plug.)" << endl;
  1491.                 continue;
  1492.             }
  1493.         }
  1494.  
  1495.         // attempt to read local transform (preferable), and possibly world transform (if it wasn't read before)
  1496.         do
  1497.         {
  1498.             MPlug mpDagPose;
  1499.             MFnDependencyNode fnDagPose;
  1500.             MPlugArray mapConnections;
  1501.             MObject moAttribWM, moAttribXM;
  1502.  
  1503.             mpToBindPose.connectedTo(mapConnections, false, true, &stat);
  1504.             if (!stat)
  1505.                 break;
  1506.  
  1507.             if (mapConnections.length() == 0)
  1508.             {
  1509.                 stat = MS::kFailure;
  1510.                 break;
  1511.             }
  1512.  
  1513.             mpDagPose = mapConnections[0];    // TODO: search through all connections instead of simply picking the first one.
  1514.  
  1515.             stat = fnDagPose.setObject(mpDagPose.node());
  1516.             if (!stat)
  1517.                 break;
  1518.  
  1519.             // world bind pose matrix (overwrites moWorldBindMatrix if read previously)
  1520.             while (moWorldBindMatrix.isNull())
  1521.             {
  1522.                 moAttribWM = fnDagPose.attribute("worldMatrix", &stat);
  1523.                 if (!stat)
  1524.                     break;
  1525.  
  1526.                 MPlug mpWorldMatrix(mpDagPose.node(), moAttribWM);
  1527.  
  1528.                 stat = mpWorldMatrix.selectAncestorLogicalIndex(mpDagPose.logicalIndex(), moAttribWM);
  1529.                 if (!stat)
  1530.                     break;
  1531.  
  1532.                 stat = mpWorldMatrix.getValue(moWorldBindMatrix);
  1533.                 if (!stat)
  1534.                     break;
  1535.             }
  1536.  
  1537.             // local bind pose matrix
  1538.             while (moLocalBindMatrix.isNull())
  1539.             {
  1540.                 moAttribXM = fnDagPose.attribute("xformMatrix", &stat);
  1541.                 if (!stat)
  1542.                     break;
  1543.  
  1544.                 MPlug mpXformMatrix(mpDagPose.node(), moAttribXM);
  1545.  
  1546.                 stat = mpXformMatrix.selectAncestorLogicalIndex(mpDagPose.logicalIndex(), moAttribXM);
  1547.                 if (!stat)
  1548.                     break;
  1549.  
  1550.                 stat = mpXformMatrix.getValue(moLocalBindMatrix);
  1551.                 if (!stat)
  1552.                     break;
  1553.             }
  1554.  
  1555.             break;
  1556.         } while (false);
  1557.  
  1558.         if (moWorldBindMatrix.isNull() && moLocalBindMatrix.isNull())
  1559.         {
  1560.             cout << "WARNING: Ignoring bone. (Neither local nor world bind matrices could be obtained.)" << endl;
  1561.             continue;
  1562.         }
  1563.  
  1564.  
  1565.  
  1566.         // get bone name
  1567.         delete[] szBone;
  1568.         szBone = NULL;
  1569.         szBone = new char[1 + fnBone.partialPathName().length()];
  1570.         if (NULL == szBone) 
  1571.         {
  1572.             hr = E_OUTOFMEMORY;
  1573.             cout << "LoadPolyMesh(): Could not allocate bone name." << endl;
  1574.             goto e_Exit;
  1575.         }
  1576.  
  1577.         strcpy(szBone, fnBone.partialPathName().asChar());
  1578.  
  1579.         for (pcBone = szBone; *pcBone != '\0'; pcBone++)    
  1580.         {    // replace '|' and ' ' characters by '_' in the maya partial pathname
  1581.             if (*pcBone == ' ' || *pcBone == '|')
  1582.                 *pcBone = '_';
  1583.         }
  1584.  
  1585.         for (iBoneIdx = 0; iBoneIdx < pShape->m_nBones; iBoneIdx++)
  1586.         {
  1587.             if (!strcmp(pShape->m_aBones[iBoneIdx].m_szName, szBone))
  1588.                 break;
  1589.         }
  1590.  
  1591.         // new bone
  1592.         if (iBoneIdx == cBonesMax)
  1593.         {    // double array size
  1594.             SBone* aBones;
  1595.             bool** aabBPT;
  1596.  
  1597.             cBonesMax *= 2;
  1598.  
  1599.             aBones = NULL;
  1600.             aBones = new SBone[cBonesMax];
  1601.             if (NULL == aBones)
  1602.             {
  1603.                 cout << "LoadPolyMesh(): Could not allocate bones." << endl;
  1604.                 goto e_Exit;
  1605.             }
  1606.  
  1607.             memcpy(aBones, pShape->m_aBones, pShape->m_nBones * sizeof(SBone));
  1608.  
  1609.             aabBPT = NULL;
  1610.             aabBPT = new bool*[cBonesMax];
  1611.             if (NULL == aabBPT)
  1612.             {
  1613.                 cout << "LoadPolyMesh(): Could not allocate bones." << endl;
  1614.                 goto e_Exit;
  1615.             }
  1616.  
  1617.             memset(aabBPT, 0, cBonesMax * sizeof(bool*));    // NULLify the table
  1618.             memcpy(aabBPT, aabBonePointTable, pShape->m_nBones * sizeof(bool*));
  1619.  
  1620.             delete[] pShape->m_aBones;
  1621.             delete[] aabBonePointTable;
  1622.  
  1623.             pShape->m_aBones = aBones;
  1624.             aabBonePointTable = aabBPT;
  1625.         }
  1626.  
  1627.  
  1628.         if (iBoneIdx == pShape->m_nBones)
  1629.         {    // initialize new bone
  1630.             aabBonePointTable[iBoneIdx] = new bool[pShape->m_nPoints];
  1631.             if (NULL == aabBonePointTable)
  1632.             {
  1633.                 cout << "LoadPolyMesh(): Could not allocate new column for bone point table." << endl;
  1634.                 goto e_Exit;
  1635.             }
  1636.  
  1637.             memset(aabBonePointTable[iBoneIdx], 0, pShape->m_nPoints * sizeof(bool));    // falsify entries
  1638.  
  1639.             // save bone name
  1640.             pShape->m_aBones[iBoneIdx].m_szName = szBone;
  1641.             g_Arrays.Add(STRING, pShape->m_aBones[iBoneIdx].m_szName);
  1642.             szBone = NULL;    // so that we won't later delete it
  1643.  
  1644.             maoBones.append(MObject::kNullObj);
  1645.             maoWorldBindMatrices.append(MObject::kNullObj);
  1646.             maoLocalBindMatrices.append(MObject::kNullObj);
  1647.  
  1648.             pShape->m_nBones++;
  1649.         }
  1650.  
  1651.         // save object & bind position
  1652.         maoBones[iBoneIdx] = fnBone.object();
  1653.         maoWorldBindMatrices[iBoneIdx] = moWorldBindMatrix;
  1654.         maoLocalBindMatrices[iBoneIdx] = moLocalBindMatrix;
  1655.  
  1656.  
  1657.         // get the points & weights
  1658.         afWeights = NULL;
  1659.         afWeights = new float[pShape->m_aBones[iBoneIdx].m_nWeights + cWeights];
  1660.         if (NULL == afWeights)
  1661.         {
  1662.             hr = E_OUTOFMEMORY;
  1663.             cout << "LoadPolyMesh(): Could not allocate memory for bone weights." << endl;
  1664.             goto e_Exit;
  1665.         }
  1666.  
  1667.         memcpy (afWeights, pShape->m_aBones[iBoneIdx].m_afWeights, pShape->m_aBones[iBoneIdx].m_nWeights * sizeof(float));
  1668.         delete[] pShape->m_aBones[iBoneIdx].m_afWeights;
  1669.         pShape->m_aBones[iBoneIdx].m_afWeights  = afWeights;
  1670.         afWeights = NULL;
  1671.  
  1672.         aiPoints = NULL;
  1673.         aiPoints = new UINT[pShape->m_aBones[iBoneIdx].m_nWeights + cWeights];
  1674.         if (NULL == aiPoints)
  1675.         {
  1676.             hr = E_OUTOFMEMORY;
  1677.             cout << "LoadPolyMesh(): Could not allocate memory for bone influenced points." << endl;
  1678.             goto e_Exit;
  1679.         }
  1680.  
  1681.         memcpy (aiPoints, pShape->m_aBones[iBoneIdx].m_aiPoints, pShape->m_aBones[iBoneIdx].m_nWeights * sizeof(UINT));
  1682.         delete[] pShape->m_aBones[iBoneIdx].m_aiPoints;
  1683.         pShape->m_aBones[iBoneIdx].m_aiPoints = aiPoints;
  1684.         aiPoints = NULL;
  1685.  
  1686.         MItGeometry itPoints(dagPath, moComponents);
  1687.         if ((UINT)itPoints.count() != cWeights)
  1688.         {
  1689.             hr = E_FAIL;
  1690.             cout << "WARNING: Ignoring bone because number of points differed from number of weights." << endl;
  1691.             goto e_Exit;
  1692.         }
  1693.         
  1694.         for (iWeight = 0; !itPoints.isDone(); itPoints.next(), iWeight++)
  1695.         {
  1696.             UINT iIndex = itPoints.index();
  1697.  
  1698.             if (iIndex >= pShape->m_nPoints)
  1699.             {
  1700.                 cout << "WARNING: Bone affects invalid index - ignoring..." << endl;
  1701.                 continue;
  1702.             }
  1703.  
  1704.             if (aabBonePointTable[iBoneIdx][iIndex])
  1705.             {
  1706.                 cout << "WARNING: Ignoring the effect of this bone on this point because the point was previously affected by this bone before." << endl;
  1707.                 continue;
  1708.             }
  1709.  
  1710.             pShape->m_aBones[iBoneIdx].m_aiPoints[pShape->m_aBones[iBoneIdx].m_nWeights] = iIndex;
  1711.             pShape->m_aBones[iBoneIdx].m_afWeights[pShape->m_aBones[iBoneIdx].m_nWeights]  = Weights[iWeight];
  1712.             pShape->m_aBones[iBoneIdx].m_nWeights++;
  1713.             pShape->m_aBones[iBoneIdx].m_nReps += pShape->m_aReps[iIndex].m_nReps;
  1714.  
  1715.             acBonesPerPoint[iIndex]++;
  1716.             aabBonePointTable[iBoneIdx][iIndex] = true;
  1717.         }
  1718.  
  1719.         if (!bRigidSkinning)
  1720.         {
  1721.             cout << "\t\t\tRigid skinning:";
  1722.             bRigidSkinning = true;
  1723.         }
  1724.         cout << " " << fnBone.name().asChar();
  1725.  
  1726.         // now add parent bone
  1727.         stat = fnDagNode.setObject(fnBone.object());
  1728.         if (!stat)
  1729.         {
  1730.             hr = E_FAIL;
  1731.             cout << "LoadPolyMesh(): Could not get bone read DAG bone object." << endl;
  1732.             goto e_Exit;
  1733.         }
  1734.  
  1735.         while (fnDagNode.parentCount() > 0 && !fnDagNode.parent(0).hasFn(MFn::kTransform))
  1736.         {
  1737.             stat = fnDagNode.setObject(fnDagNode.parent(0));
  1738.             if (!stat)
  1739.             {
  1740.                 hr = E_FAIL;
  1741.                 cout << "LoadPolyMesh(): Could not get parent object." << endl;
  1742.                 goto e_Exit;
  1743.             }
  1744.         }
  1745.  
  1746.         // get parent bone name
  1747.         if (fnDagNode.parentCount() == 0)
  1748.             continue;
  1749.  
  1750.         stat = fnDagNode.setObject(fnDagNode.parent(0));
  1751.         if (!stat)
  1752.         {
  1753.             hr = E_FAIL;
  1754.             cout << "LoadPolyMesh(): Could not get parent object." << endl;
  1755.             goto e_Exit;
  1756.         }
  1757.  
  1758.         stat = fnDagNode.getPath(dagPath);
  1759.         if (!stat)
  1760.         {
  1761.             hr = E_FAIL;
  1762.             cout << "LoadPolyMesh(): Could not get parent's path." << endl;
  1763.             goto e_Exit;
  1764.         }
  1765.  
  1766.         delete[] szBone;
  1767.         szBone = NULL;
  1768.         szBone = new char[1 + dagPath.partialPathName().length()];
  1769.         if (NULL == szBone) 
  1770.         {
  1771.             hr = E_OUTOFMEMORY;
  1772.             cout << "LoadPolyMesh(): Could not allocate bone name." << endl;
  1773.             goto e_Exit;
  1774.         }
  1775.  
  1776.         strcpy(szBone, dagPath.partialPathName().asChar());
  1777.  
  1778.         for (pcBone = szBone; *pcBone != '\0'; pcBone++)    
  1779.         {    // replace '|' and ' ' characters by '_' in the maya partial pathname
  1780.             if (*pcBone == ' ' || *pcBone == '|')
  1781.                 *pcBone = '_';
  1782.         }
  1783.  
  1784.         for (iBoneIdx = 0; iBoneIdx < pShape->m_nBones; iBoneIdx++)
  1785.         {
  1786.             if (!strcmp(pShape->m_aBones[iBoneIdx].m_szName, szBone))
  1787.                 break;
  1788.         }
  1789.  
  1790.         // new bone
  1791.         if (iBoneIdx == cBonesMax)
  1792.         {    // double array size
  1793.             SBone* aBones;
  1794.             bool** aabBPT;
  1795.  
  1796.             cBonesMax *= 2;
  1797.  
  1798.             aBones = NULL;
  1799.             aBones = new SBone[cBonesMax];
  1800.             if (NULL == aBones)
  1801.             {
  1802.                 cout << "LoadPolyMesh(): Could not allocate bones." << endl;
  1803.                 goto e_Exit;
  1804.             }
  1805.  
  1806.             memcpy(aBones, pShape->m_aBones, pShape->m_nBones * sizeof(SBone));
  1807.  
  1808.             aabBPT = NULL;
  1809.             aabBPT = new bool*[cBonesMax];
  1810.             if (NULL == aabBPT)
  1811.             {
  1812.                 cout << "LoadPolyMesh(): Could not allocate bones." << endl;
  1813.                 goto e_Exit;
  1814.             }
  1815.  
  1816.             memset(aabBPT, 0, cBonesMax * sizeof(bool*));    // NULLify the table
  1817.             memcpy(aabBPT, aabBonePointTable, pShape->m_nBones * sizeof(bool*));
  1818.  
  1819.             delete[] pShape->m_aBones;
  1820.             delete[] aabBonePointTable;
  1821.  
  1822.             pShape->m_aBones = aBones;
  1823.             aabBonePointTable = aabBPT;
  1824.         }
  1825.  
  1826.  
  1827.         if (iBoneIdx == pShape->m_nBones)
  1828.         {    // initialize new bone
  1829.             aabBonePointTable[iBoneIdx] = new bool[pShape->m_nPoints];
  1830.             if (NULL == aabBonePointTable)
  1831.             {
  1832.                 cout << "LoadPolyMesh(): Could not allocate new column for bone point table." << endl;
  1833.                 goto e_Exit;
  1834.             }
  1835.  
  1836.             memset(aabBonePointTable[iBoneIdx], 0, pShape->m_nPoints * sizeof(bool));    // falsify entries
  1837.  
  1838.             // save bone name
  1839.             pShape->m_aBones[iBoneIdx].m_szName = szBone;
  1840.             g_Arrays.Add(STRING, pShape->m_aBones[iBoneIdx].m_szName);
  1841.             szBone = NULL;    // so that we won't later delete it
  1842.  
  1843.  
  1844.             // offset matrix - it's a subtle point that we need to overwrite this each time (especially in the case of rigid skinning)
  1845.             stat = (mmWorldTransform).get(pShape->m_aBones[iBoneIdx].m_aafOffset);
  1846.             if (!stat)
  1847.             {
  1848.                 hr = E_FAIL;
  1849.                 cout << "LoadPolyMesh(): Could not get bind pose transform." << endl;
  1850.                 goto e_Exit;
  1851.             }
  1852.  
  1853.             maoBones.append(MObject::kNullObj);
  1854.             maoWorldBindMatrices.append(MObject::kNullObj);
  1855.             maoLocalBindMatrices.append(MObject::kNullObj);
  1856.  
  1857.             pShape->m_nBones++;
  1858.         }
  1859.  
  1860.  
  1861.         // get the points & weights
  1862.         afWeights = NULL;
  1863.         afWeights = new float[pShape->m_aBones[iBoneIdx].m_nWeights + cWeights];
  1864.         if (NULL == afWeights)
  1865.         {
  1866.             hr = E_OUTOFMEMORY;
  1867.             cout << "LoadPolyMesh(): Could not allocate memory for bone weights." << endl;
  1868.             goto e_Exit;
  1869.         }
  1870.  
  1871.         memcpy (afWeights, pShape->m_aBones[iBoneIdx].m_afWeights, pShape->m_aBones[iBoneIdx].m_nWeights * sizeof(float));
  1872.         delete[] pShape->m_aBones[iBoneIdx].m_afWeights;
  1873.         pShape->m_aBones[iBoneIdx].m_afWeights  = afWeights;
  1874.         afWeights = NULL;
  1875.  
  1876.         aiPoints = NULL;
  1877.         aiPoints = new UINT[pShape->m_aBones[iBoneIdx].m_nWeights + cWeights];
  1878.         if (NULL == aiPoints)
  1879.         {
  1880.             hr = E_OUTOFMEMORY;
  1881.             cout << "LoadPolyMesh(): Could not allocate memory for bone influenced points." << endl;
  1882.             goto e_Exit;
  1883.         }
  1884.  
  1885.         memcpy (aiPoints, pShape->m_aBones[iBoneIdx].m_aiPoints, pShape->m_aBones[iBoneIdx].m_nWeights * sizeof(UINT));
  1886.         delete[] pShape->m_aBones[iBoneIdx].m_aiPoints;
  1887.         pShape->m_aBones[iBoneIdx].m_aiPoints = aiPoints;
  1888.         aiPoints = NULL;
  1889.  
  1890.         itPoints.reset();
  1891.  
  1892.         for (iWeight = 0; !itPoints.isDone(); itPoints.next(), iWeight++)
  1893.         {
  1894.             UINT iIndex = itPoints.index();
  1895.  
  1896.             if (iIndex >= pShape->m_nPoints)
  1897.             {
  1898.                 cout << "WARNING: Bone affects invalid index - ignoring..." << endl;
  1899.                 continue;
  1900.             }
  1901.  
  1902.             if (aabBonePointTable[iBoneIdx][iIndex])
  1903.             {
  1904.                 cout << "WARNING: Ignoring the effect of this bone on this point because the point was previously affected by this bone before." << endl;
  1905.                 continue;
  1906.             }
  1907.  
  1908.             if (1.0f - Weights[iWeight] == 0.0f)
  1909.                 continue;
  1910.  
  1911.             pShape->m_aBones[iBoneIdx].m_aiPoints[pShape->m_aBones[iBoneIdx].m_nWeights] = iIndex;
  1912.             pShape->m_aBones[iBoneIdx].m_afWeights[pShape->m_aBones[iBoneIdx].m_nWeights] = 1.0f - Weights[iWeight];
  1913.             pShape->m_aBones[iBoneIdx].m_nWeights++;
  1914.             pShape->m_aBones[iBoneIdx].m_nReps += pShape->m_aReps[iIndex].m_nReps;
  1915.  
  1916.             acBonesPerPoint[iIndex]++;
  1917.  
  1918.             aabBonePointTable[iBoneIdx][iIndex] = true;
  1919.         }
  1920.  
  1921.     }
  1922.  
  1923.  
  1924. e_ExitRigidSkinning:
  1925.  
  1926.     if (bRigidSkinning)
  1927.         cout << endl;
  1928.  
  1929.     // OTHER SKINNING
  1930.  
  1931.     stat = itClusters.reset(MFn::kWeightGeometryFilt);
  1932.     if (!stat)
  1933.     {
  1934.         cout << "WARNING: Could not search weight geometry filters." << endl;
  1935.         goto e_ExitSkinning;
  1936.     }
  1937.  
  1938.     for (bUnkownSkinning = false; !itClusters.isDone(); itClusters.next()) 
  1939.     {
  1940.         if (itClusters.item().hasFn(MFn::kJointCluster))
  1941.             continue;
  1942.  
  1943.         stat = fnCluster.setObject(itClusters.item());
  1944.         if (!stat)
  1945.         {
  1946.             cout << "WARNING: Ignoring this weight geometry filter because couldn't read the object." << endl;
  1947.             continue;
  1948.         }
  1949.  
  1950.         cout << "\t\t\tUnknown skinning: (" << fnCluster.object().apiTypeStr() << ")." << endl;
  1951.  
  1952.         if (!bUnkownSkinning)
  1953.             bUnkownSkinning = true;
  1954.     }
  1955.  
  1956.  
  1957. e_ExitSkinning:
  1958.  
  1959.  
  1960.     if ((UINT)maoBones.length() != pShape->m_nBones)    // sanity check
  1961.     {
  1962.         cout << "LoadPolyMesh(): Aborting because there was a mismatch in the length of the bone- and the bone object- arrays." << endl;
  1963.         goto e_Exit;
  1964.     }
  1965.  
  1966.     amtmBonePositions = new MTransformationMatrix[pShape->m_nBones];
  1967.     if (NULL == amtmBonePositions)
  1968.     {
  1969.         cout << "LoadPolyMesh(): Could not allocate bone transformation array." << endl;
  1970.         goto e_Exit;
  1971.     }
  1972.  
  1973.  
  1974.     // create bone remap array based on descending hierarchical order
  1975.     for (iBone = 0; iBone < pShape->m_nBones; iBone++)
  1976.     {
  1977.         if (maoBones[iBone].isNull() || !maoBones[iBone].hasFn(MFn::kJoint))
  1978.             continue;
  1979.  
  1980.         stat = fnBone.setObject(maoBones[iBone]);
  1981.         if (!stat)
  1982.             continue;
  1983.  
  1984.         amtmBonePositions[iBone] = fnBone.transformation();
  1985.  
  1986.         if (maoLocalBindMatrices[iBone].isNull())
  1987.             continue;
  1988.         
  1989.         stat = fnMatrix.setObject(maoLocalBindMatrices[iBone]);
  1990.         if (!stat)
  1991.             continue;
  1992.  
  1993.         stat = fnBone.set(fnMatrix.transformation());
  1994.         if (!stat)
  1995.             continue;
  1996.     }
  1997.  
  1998.     for (; !itBones.isDone(); itBones.next())
  1999.     {
  2000.         MObject moBone = itBones.item();
  2001.  
  2002.         for (iBone = 0; iBone < pShape->m_nBones; iBone++)
  2003.         {
  2004.             if (!maoLocalBindMatrices[iBone].isNull())
  2005.                 break;
  2006.  
  2007.             if (moBone == maoBones[iBone])
  2008.             {
  2009.                 maiBoneRemap.append(iBone);
  2010.                 break;
  2011.             }
  2012.         }
  2013.     }
  2014.  
  2015.     for (iBoneRemap = 0; iBoneRemap < maiBoneRemap.length(); iBoneRemap++)
  2016.     {
  2017.         MDagPath mdpBone;
  2018.         iBone = maiBoneRemap[iBoneRemap];
  2019.  
  2020.         if (maoBones[iBone].isNull() || !maoBones[iBone].hasFn(MFn::kJoint))
  2021.             continue;
  2022.  
  2023.         stat = fnBone.setObject(maoBones[iBone]);
  2024.         if (!stat)
  2025.             continue;
  2026.  
  2027.         stat = fnBone.getPath(mdpBone);
  2028.         if (!stat)
  2029.             continue;
  2030.  
  2031.         if (maoWorldBindMatrices[iBone].isNull())
  2032.             continue;
  2033.         
  2034.         stat = fnMatrix.setObject(maoWorldBindMatrices[iBone]);
  2035.         if (!stat)
  2036.             continue;
  2037.  
  2038.         stat = fnBone.set(MTransformationMatrix(fnMatrix.matrix() * mdpBone.exclusiveMatrixInverse()));
  2039.         if (!stat)
  2040.             continue;
  2041.     }
  2042.  
  2043.  
  2044.     for (iBone = 0; iBone < pShape->m_nBones; iBone++)
  2045.     {
  2046.         MMatrix mmBoneOffsetMatrix = mmWorldTransform;
  2047.         MDagPath mdpBone;
  2048.         
  2049.         do 
  2050.         {
  2051.             MDagPath mdpBone;
  2052.  
  2053.             if (maoBones[iBone].isNull())
  2054.                 break;
  2055.  
  2056.             stat = MDagPath::getAPathTo(maoBones[iBone], mdpBone);
  2057.             if (!stat)
  2058.             {
  2059.                 cout << "WARNING: Could not get DAG path to bone.  Skinning may look incorrect." << endl;
  2060.                 break;
  2061.             }
  2062.  
  2063.             mmBoneOffsetMatrix = mmBoneOffsetMatrix * mdpBone.inclusiveMatrix().inverse();
  2064.         } while (false);
  2065.  
  2066.         mmBoneOffsetMatrix.get(pShape->m_aBones[iBone].m_aafOffset);
  2067.     }
  2068.  
  2069.  
  2070.     stat = fnMesh.syncObject();
  2071.     if (!stat)
  2072.     {
  2073.         cout << "LoadPolyMesh(): Could not sync mesh object." << endl;
  2074.         goto e_ExitGeometry;
  2075.     }
  2076.  
  2077.  
  2078.     // POINTS
  2079.     stat = fnMesh.getPoints(mfpaPoints);
  2080.     if (!stat)
  2081.     {
  2082.         cout << "WARNING: Aborting because vertices could not be read." << endl;
  2083.         goto e_ExitGeometry;
  2084.     }
  2085.  
  2086.     if (mfpaPoints.length() != pShape->m_nPoints)
  2087.     {
  2088.         cout << "WARNING: Aborting because point array length(" << mfpaPoints.length() << ") did not match number of points(" << pShape->m_nPoints << ")." << endl;
  2089.         goto e_ExitGeometry;
  2090.     }
  2091.  
  2092.     for (iVert = 0; iVert < pShape->m_nPoints; iVert++) 
  2093.     {
  2094.         pShape->m_aPoints[iVert].vec[0] = mfpaPoints[iVert][0];
  2095.         pShape->m_aPoints[iVert].vec[1] = mfpaPoints[iVert][1];
  2096.         pShape->m_aPoints[iVert].vec[2] = mfpaPoints[iVert][2];
  2097.     }
  2098.  
  2099.  
  2100.     // NORMALS
  2101.     if (pShape->m_nNormals == 0)
  2102.         goto e_ExitNormals;
  2103.  
  2104.     stat = fnMesh.getNormals(mfvaNormals);
  2105.     if (!stat)
  2106.     {
  2107.         cout << "LoadPolyMesh(): Could not be read normals." << endl;
  2108.         goto e_ExitGeometry;
  2109.     }
  2110.  
  2111.     if (mfvaNormals.length() != pShape->m_nNormals)
  2112.     {
  2113.         cout << "LoadPolyMesh: Normal array length did not match number of normals." << endl;
  2114.         goto e_ExitGeometry;
  2115.     }
  2116.  
  2117.     for (iNorm = 0; iNorm < pShape->m_nNormals; iNorm++)    
  2118.     {
  2119.         pShape->m_aNormals[iNorm].vec[0] = mfvaNormals[iNorm][0];
  2120.         pShape->m_aNormals[iNorm].vec[1] = mfvaNormals[iNorm][1];
  2121.         pShape->m_aNormals[iNorm].vec[2] = mfvaNormals[iNorm][2];
  2122.     }
  2123.  
  2124. e_ExitNormals:
  2125.  
  2126.  
  2127.     // UVs
  2128.     if (pShape->m_nUVs == 0)
  2129.         goto e_ExitUVs;
  2130.  
  2131.     stat = fnMesh.getUVs(mfaUs, mfaVs);
  2132.     if (!stat)
  2133.     {
  2134.         cout << "WARNING: Aborting because UVs could not be read." << endl;
  2135.         goto e_ExitGeometry;
  2136.     }
  2137.  
  2138.     if (mfaUs.length() != pShape->m_nUVs || mfaVs.length() != pShape->m_nUVs)    // sanity check
  2139.     {
  2140.         cout << "WARNING: Aborting because UV array length did not match number of UVs." << endl;
  2141.         goto e_ExitGeometry;
  2142.     }
  2143.  
  2144.     for (iUV = 0; iUV < pShape->m_nUVs; iUV++)    
  2145.     {
  2146.         pShape->m_aUVs[iUV].vec[0] = mfaUs[iUV];
  2147.         pShape->m_aUVs[iUV].vec[1] = mfaVs[iUV];
  2148.     }
  2149.  
  2150. e_ExitUVs:
  2151.  
  2152.  
  2153. e_ExitGeometry:
  2154.  
  2155.     for (iBone = 0; iBone < pShape->m_nBones; iBone++)
  2156.     {
  2157.         if (maoBones[iBone].isNull() || !maoBones[iBone].hasFn(MFn::kJoint))
  2158.             continue;
  2159.  
  2160.         stat = fnBone.setObject(maoBones[iBone]);
  2161.         if (!stat)
  2162.             continue;
  2163.  
  2164.         stat = fnBone.set(amtmBonePositions[iBone]);
  2165.         if (!stat)
  2166.             continue;
  2167.     }
  2168.  
  2169.  
  2170.     if (FAILED(hr))
  2171.     {
  2172.         cout << "LoadPolyMesh(): Could not load geometry." << endl;
  2173.         goto e_Exit;
  2174.     }
  2175.  
  2176.  
  2177.  
  2178.     // ensure that weights sum to 1 by adding, if necessary, an EXTRA BONE (corresponding to this mesh's transform)
  2179.     if (pShape->m_nBones > 0)
  2180.     {
  2181.         UINT nWeights = 0;
  2182.         UINT nReps = 0;
  2183.         
  2184.         afWeights = NULL;
  2185.         if (NULL == (afWeights = new float[pShape->m_nPoints]))
  2186.         {
  2187.             hr = E_OUTOFMEMORY;
  2188.             cout << "LoadPolyMesh(): Could not allocate extra bone's weight array." << endl;
  2189.             goto e_Exit;
  2190.         }
  2191.         memset(afWeights, 0, pShape->m_nPoints * sizeof(float));    // zero out array
  2192.  
  2193.         aiPoints = NULL;
  2194.         if (NULL == (aiPoints = new UINT[pShape->m_nPoints]))
  2195.         {
  2196.             hr = E_OUTOFMEMORY;
  2197.             cout << "LoadPolyMesh(): Could not allocate extra bone's point index array." << endl;
  2198.             goto e_Exit;
  2199.         }
  2200.  
  2201.         abBonePointArray = NULL;
  2202.         if (NULL == (abBonePointArray = new bool[pShape->m_nPoints]))
  2203.         {
  2204.             hr = E_OUTOFMEMORY;
  2205.             cout << "LoadPolyMesh(): Could not allocate extra bone's point flag array." << endl;
  2206.             goto e_Exit;
  2207.         }
  2208.         memset(abBonePointArray, 0, pShape->m_nPoints * sizeof(bool));    // falsify array
  2209.  
  2210.         for (iBone = 0; iBone < pShape->m_nBones; iBone++)
  2211.         {
  2212.             for (iIndex = 0; iIndex < pShape->m_aBones[iBone].m_nWeights; iIndex++)
  2213.             {
  2214.                 afWeights[pShape->m_aBones[iBone].m_aiPoints[iIndex]] += pShape->m_aBones[iBone].m_afWeights[iIndex];
  2215.             }
  2216.         }
  2217.  
  2218.         for (nWeights = 0, nReps = 0, iVert = 0; iVert < pShape->m_nPoints; iVert++)
  2219.         {
  2220.             if (afWeights[iVert] < 1.0f)
  2221.             {
  2222.                 aiPoints[nWeights] = iVert;
  2223.                 afWeights[nWeights] = 1.0f - afWeights[iVert];
  2224.                 nReps += pShape->m_aReps[iVert].m_nReps;
  2225.                 nWeights++;
  2226.                 acBonesPerPoint[iVert]++;
  2227.                 abBonePointArray[iVert] = true;
  2228.             }
  2229.         }
  2230.  
  2231.         if (nWeights > 0)
  2232.         {
  2233.             // get bone name
  2234.             delete[] szBone;
  2235.             szBone = NULL;
  2236.             szBone = new char[1 + mdpTransform.partialPathName().length()];
  2237.             if (NULL == szBone) 
  2238.             {
  2239.                 hr = E_OUTOFMEMORY;
  2240.                 cout << "LoadPolyMesh(): Could not allocate bone name." << endl;
  2241.                 goto e_Exit;
  2242.             }
  2243.  
  2244.             strcpy(szBone, mdpTransform.partialPathName().asChar());
  2245.  
  2246.             for (pcBone = szBone; *pcBone != '\0'; pcBone++)    
  2247.             {    // replace '|' and ' ' characters by '_' in the maya partial pathname
  2248.                 if (*pcBone == ' ' || *pcBone == '|')
  2249.                     *pcBone = '_';
  2250.             }
  2251.  
  2252.             iBoneIdx = pShape->m_nBones;
  2253.  
  2254.             // new bone
  2255.             if (iBoneIdx == cBonesMax)
  2256.             {    // double array size
  2257.                 SBone* aBones;
  2258.                 bool** aabBPT;
  2259.  
  2260.                 cBonesMax *= 2;
  2261.  
  2262.                 aBones = NULL;
  2263.                 aBones = new SBone[cBonesMax];
  2264.                 if (NULL == aBones)
  2265.                 {
  2266.                     cout << "LoadPolyMesh(): Could not allocate bones." << endl;
  2267.                     goto e_Exit;
  2268.                 }
  2269.  
  2270.                 memcpy(aBones, pShape->m_aBones, pShape->m_nBones * sizeof(SBone));
  2271.  
  2272.                 aabBPT = NULL;
  2273.                 aabBPT = new bool*[cBonesMax];
  2274.                 if (NULL == aabBPT)
  2275.                 {
  2276.                     cout << "LoadPolyMesh(): Could not allocate bones." << endl;
  2277.                     goto e_Exit;
  2278.                 }
  2279.  
  2280.                 memset(aabBPT, 0, cBonesMax * sizeof(bool*));    // NULLify the table
  2281.                 memcpy(aabBPT, aabBonePointTable, pShape->m_nBones * sizeof(bool*));
  2282.  
  2283.                 delete[] pShape->m_aBones;
  2284.                 delete[] aabBonePointTable;
  2285.  
  2286.                 pShape->m_aBones = aBones;
  2287.                 aabBonePointTable = aabBPT;
  2288.             }
  2289.  
  2290.  
  2291.             if (iBoneIdx == pShape->m_nBones)
  2292.             {    // initialize new bone
  2293.                 // save bone name
  2294.                 pShape->m_aBones[iBoneIdx].m_szName = szBone;
  2295.                 g_Arrays.Add(STRING, pShape->m_aBones[iBoneIdx].m_szName);
  2296.                 szBone = NULL;    // so that we won't later delete it
  2297.  
  2298.                 pShape->m_nBones++;
  2299.             }
  2300.  
  2301.             pShape->m_aBones[iBoneIdx].m_nWeights = nWeights;
  2302.             pShape->m_aBones[iBoneIdx].m_nReps = nReps;
  2303.  
  2304.             pShape->m_aBones[iBoneIdx].m_afWeights = afWeights;
  2305.             afWeights = NULL;
  2306.  
  2307.             pShape->m_aBones[iBoneIdx].m_aiPoints = aiPoints;
  2308.             aiPoints = NULL;
  2309.  
  2310.             aabBonePointTable[iBoneIdx] = abBonePointArray;
  2311.             abBonePointArray = NULL;
  2312.         }
  2313.     }
  2314.  
  2315.  
  2316.     // MAX BONES PER POINT
  2317.     pShape->m_nMaxBonesPerPoint = 0;
  2318.     for (iVert = 0; iVert < pShape->m_nPoints; iVert++)
  2319.     {
  2320.         if (pShape->m_nMaxBonesPerPoint < acBonesPerPoint[iVert])
  2321.             pShape->m_nMaxBonesPerPoint = acBonesPerPoint[iVert];
  2322.     }
  2323.  
  2324.     // MAX BONES PER FACE
  2325.     pShape->m_nMaxBonesPerFace = 0;
  2326.     for (iFace = 0; iFace < pShape->m_nFaces; iFace++)
  2327.     {
  2328.         UINT cBonesPerFace = 0;
  2329.  
  2330.         for (iBone = 0; iBone < pShape->m_nBones; iBone++)
  2331.         {
  2332.             for (iIndex = 0; iIndex < pShape->m_aFaces[iFace].m_nIndices; iIndex++)
  2333.             {
  2334.                 if (aabBonePointTable[iBone][pShape->m_aReps[pShape->m_aFaces[iFace].m_aIndices[iIndex]].m_iFirst])
  2335.                 {
  2336.                     cBonesPerFace++;
  2337.                     break;
  2338.                 }
  2339.             }
  2340.         }
  2341.  
  2342.         if (pShape->m_nMaxBonesPerFace < cBonesPerFace)
  2343.             pShape->m_nMaxBonesPerFace = cBonesPerFace;
  2344.     }
  2345.  
  2346.     pShape->m_kType                = SMesh::POLY_MESH;        // mesh type
  2347.  
  2348.     cout << "\t\t\t" 
  2349.         << pShape->m_nReps << " rep(s), "
  2350.         << pShape->m_nPoints << " point(s), "
  2351.         << pShape->m_nNormals << " normal(s), "
  2352.         << pShape->m_nUVs << " UV(s), "
  2353.         << pShape->m_nGroups << " material(s), "
  2354.         << pShape->m_nFaces << " face(s), "
  2355.         << pShape->m_nBones << " bone(s), "
  2356.         << pShape->m_nMaxBonesPerPoint << " max bones/point, "
  2357.         << pShape->m_nMaxBonesPerFace << " max bones/face."
  2358.         << endl;
  2359.  
  2360.     
  2361. e_Exit:
  2362.  
  2363.     if (NULL != aabBonePointTable)
  2364.     {
  2365.         for (iBone = 0; iBone < cBonesMax; iBone++)
  2366.         {
  2367.             delete[] aabBonePointTable[iBone];
  2368.         }
  2369.  
  2370.         delete[] aabBonePointTable;
  2371.     }
  2372.  
  2373.     delete[] acBonesPerPoint;
  2374.     delete[] szBone;
  2375.     delete[] amtmBonePositions;
  2376.     delete[] afWeights;
  2377.     delete[] aiPoints;
  2378.     delete[] abBonePointArray;
  2379.  
  2380.     return    hr;
  2381. }
  2382.  
  2383.  
  2384.  
  2385. bool    IsPatchMesh
  2386.         (
  2387.             MDagPath& mdpNurbs
  2388.         ) 
  2389. {
  2390.     MFnNurbsSurface    fnNurbs;
  2391.  
  2392.     if (!mdpNurbs.hasFn(MFn::kNurbsSurface))
  2393.         return false;        // not a nurbs surface
  2394.  
  2395.     if (!fnNurbs.setObject(mdpNurbs))
  2396.         return false;
  2397.  
  2398.     if (fnNurbs.degreeU() != 3 || fnNurbs.degreeV() != 3)    
  2399.         return false;        // not a bicubic surface
  2400.  
  2401.     int    kFormInU = fnNurbs.formInU();
  2402.     int    kFormInV = fnNurbs.formInV();
  2403.  
  2404.     if (kFormInU == MFnNurbsSurface::kInvalid || kFormInV == MFnNurbsSurface::kInvalid)
  2405.         return false;        // surface has invalid form
  2406.  
  2407.     if (kFormInU == MFnNurbsSurface::kPeriodic || kFormInV == MFnNurbsSurface::kPeriodic)
  2408.         return false;        // can't handle periodic surfaces
  2409.     
  2410.     int    cCVsInU    = fnNurbs.numCVsInU();
  2411.     int    cCVsInV    = fnNurbs.numCVsInV();
  2412.  
  2413.     if ((cCVsInU - 1) % 3 != 0 || (cCVsInV - 1) % 3 != 0)
  2414.         return false;        // invalid control point count (we only deal with quad patches)
  2415.  
  2416.     int    cSpansInU = (cCVsInU - 1) / 3;
  2417.     int    cSpansInV = (cCVsInV - 1) / 3;
  2418.  
  2419.     if (cSpansInU <= 0 || cSpansInV <= 0)
  2420.         return false;        // invalid span count
  2421.  
  2422.     return true;            // all tests passed
  2423. }
  2424.  
  2425.  
  2426.  
  2427.  
  2428.  
  2429.  
  2430.  
  2431.  
  2432.  
  2433.  
  2434. HRESULT    LoadPatchMesh
  2435.         (
  2436.             MDagPath&    mdpTransform, 
  2437.             MDagPath&    mdpNurbs,
  2438.             SMesh*    pShape
  2439.         ) 
  2440. {
  2441.     HRESULT hr = S_OK;
  2442.     MStatus stat = MS::kSuccess;
  2443.  
  2444.  
  2445.  
  2446.     MFnTransform fnTransform;
  2447.     MFnNurbsSurface fnNurbs;
  2448.  
  2449.     MDagPath mdpMesh;
  2450.     MObject moMesh = MObject::kNullObj;
  2451.  
  2452.  
  2453.     if (!mdpTransform.hasFn(MFn::kTransform))
  2454.     {
  2455.         hr = E_FAIL;
  2456.         cout << "LoadPatchMesh(): Input path is not a transform as expected.  Aborting..." << endl;
  2457.         goto e_Exit;
  2458.     }
  2459.  
  2460.     stat = fnTransform.setObject(mdpTransform);
  2461.     if (!stat)
  2462.     {
  2463.         hr = E_FAIL;
  2464.         cout << "LoadPatchMesh(): Could not access transform object through function set.  Aborting..." << endl;
  2465.         goto e_Exit;
  2466.     }
  2467.  
  2468.     if (!mdpNurbs.hasFn(MFn::kNurbsSurface))
  2469.     {
  2470.         hr = E_FAIL;
  2471.         cout << "LoadPatchMesh(): Input path is not a NURBS surface as expected.  Aborting..." << endl;
  2472.         goto e_Exit;
  2473.     }
  2474.  
  2475.     stat = fnNurbs.setObject(mdpNurbs);
  2476.     if (!stat)
  2477.     {
  2478.         hr = E_FAIL;
  2479.         cout << "LoadPatchMesh(): Could not access NURBS surface object through function set.  Aborting..." << endl;
  2480.         goto e_Exit;
  2481.     }
  2482.  
  2483.     if (g_bExportPatches)
  2484.         goto e_PatchExport;
  2485.  
  2486.     // TESSELATE
  2487.     moMesh = fnNurbs.tesselate(MTesselationParams::fsDefaultTesselationParams, mdpTransform.node(), &stat);
  2488.     if (!stat)
  2489.     {
  2490.         hr = E_FAIL;
  2491.         cout << "LoadPatchMesh(): Could not tesselate NURBS surface.  Aborting..." << endl;
  2492.         goto e_ExitTesselate;
  2493.     }
  2494.  
  2495.     if (!moMesh.hasFn(MFn::kMesh))
  2496.     {
  2497.         hr = E_FAIL;
  2498.         cout << "LoadPatchMesh(): Tesselation did not produce a mesh.  Aborting..." << endl;
  2499.         goto e_ExitTesselate;
  2500.     }
  2501.  
  2502.     stat = MDagPath::getAPathTo(moMesh, mdpMesh);
  2503.     if (!stat)
  2504.     {
  2505.         hr = E_FAIL;
  2506.         cout << "LoadPatchMesh(): Could not a DAG path to the tesselated mesh.  Aborting..." << endl;
  2507.         goto e_ExitTesselate;
  2508.     }
  2509.  
  2510.     hr = LoadPolyMesh(mdpTransform, mdpMesh, pShape);
  2511.     if (FAILED(hr))
  2512.     {
  2513.         cout << "LoadPatchMesh(): Could not load tesselated mesh.  Aborting..." << endl;
  2514.         goto e_ExitTesselate;
  2515.     }
  2516.  
  2517.  
  2518. e_ExitTesselate:
  2519.  
  2520.     if (!moMesh.isNull() && !fnTransform.object().isNull())
  2521.     {
  2522.         stat = fnTransform.removeChild(moMesh);
  2523.         if (!stat)
  2524.             cout << "WARNING: Could not remove tesselated mesh object." << endl;
  2525.     }
  2526.  
  2527.     goto e_Exit;
  2528.  
  2529. e_PatchExport:
  2530.  
  2531. /*    
  2532.     // set up references
  2533.  
  2534.  
  2535.  
  2536.  
  2537.     // ensure that shape is a nurbs surface
  2538.     MObject    objNurb;
  2539.  
  2540.     DT_ATTEMPT(DtExt_ShapeGetShapeNode(iShape, objNurb));
  2541.  
  2542.     ASSERT(objNurb.hasFn(MFn::kNurbsSurface),    
  2543.                 "Not a nurb surface");
  2544.  
  2545.     MFnNurbsSurface    fnNurb(objNurb);
  2546.  
  2547.     // ensure that surface is bicubic
  2548.     ASSERT(fnNurb.degreeU() == 3 && fnNurb.degreeV() == 3,    
  2549.                 "Not a bicubic surface");
  2550.  
  2551.     // ensure correct form in U and V 
  2552.     int    kFormInU    = fnNurb.formInU();
  2553.     int    kFormInV    = fnNurb.formInV();
  2554.  
  2555.     ASSERT(kFormInU    == MFnNurbsSurface::kOpen || kFormInU == MFnNurbsSurface::kClosed,
  2556.                 "Invalid form in U");
  2557.  
  2558.     ASSERT(kFormInV == MFnNurbsSurface::kOpen || kFormInV == MFnNurbsSurface::kClosed,
  2559.                 "Invalid form in V");
  2560.  
  2561.     // ensure that surface is a quad mesh
  2562.     int    cCVsInU    = fnNurb.numCVsInU();
  2563.     int    cCVsInV    = fnNurb.numCVsInV();
  2564.  
  2565.     ASSERT((cCVsInU - 1) % 3 == 0 && (cCVsInV - 1) % 3 == 0,
  2566.                 "Invalid CV count");
  2567.  
  2568.     // ensure that there is at least one patch
  2569.     int    cSpansInU    = (cCVsInU - 1) / 3;
  2570.     int    cSpansInV    = (cCVsInV - 1) / 3;
  2571.  
  2572.     ASSERT(cSpansInU > 0 && cSpansInV > 0, 
  2573.                 "Invalid span count");
  2574.  
  2575.  
  2576.     // control vertices
  2577.  
  2578.     MPointArray rgCVs;
  2579.  
  2580.     fnNurb.getCVs(rgCVs);
  2581.  
  2582.     cVertices    = (int)rgCVs.length();
  2583.     rgVertices    = new DtVec3f[cVertices];
  2584.  
  2585.     ASSERT(rgVertices, 
  2586.                 "Can't allocate memory for vertex array");
  2587.  
  2588.     for (UINT iVertex = 0; iVertex < cVertices; iVertex++) 
  2589.     {
  2590.         rgVertices[iVertex].vec[0]    = (float)rgCVs[iVertex][0];
  2591.         rgVertices[iVertex].vec[1]    = (float)rgCVs[iVertex][1];
  2592.         rgVertices[iVertex].vec[2]    = (float)rgCVs[iVertex][2];
  2593.     }
  2594.  
  2595.  
  2596.  
  2597.     // texture coordinates
  2598.     cTexCoords    = (int)rgCVs.length();
  2599.     rgTexCoords    = new DtVec2f[cTexCoords];
  2600.  
  2601.     ASSERT(rgTexCoords, 
  2602.                 "Can't allocate memory for texture coordinate array");
  2603.  
  2604.     for (int iCVInU = 0, iTexCoord = 0; iCVInU < cCVsInU; iCVInU++)
  2605.     {
  2606.         for (int iCVInV = 0; iCVInV < cCVsInV; iCVInV++, iTexCoord++)
  2607.         {
  2608.             rgTexCoords[iTexCoord].vec[0] =  ((float)iCVInU) / ((float)(cCVsInU - 1));
  2609.             rgTexCoords[iTexCoord].vec[1] =  ((float)iCVInV) / ((float)(cCVsInV - 1));
  2610.         }
  2611.     }
  2612.  
  2613.  
  2614.  
  2615.     // face info
  2616.     cFaces    = cSpansInU * cSpansInV;
  2617.     rgFaces    = new SFace[cFaces];
  2618.  
  2619.     ASSERT(rgFaces, 
  2620.                 "Can't allocate memory for patch array");
  2621.  
  2622.  
  2623.     cFaceIndices    = 0;
  2624.             
  2625.     for (int iSpanInU = 0, iPatch = 0; iSpanInU < cSpansInU; iSpanInU++) 
  2626.     {
  2627.         int iCVIndexInU    = iSpanInU * 3;
  2628.  
  2629.         for (int iSpanInV = 0; iSpanInV < cSpansInV; iSpanInV++, iPatch++) 
  2630.         {
  2631.             int iCVIndexInV    = iSpanInV * 3;
  2632.  
  2633.             rgFaces[iPatch].m_nIndices        = 16;
  2634.             rgFaces[iPatch].m_aIndices        = new UINT[rgFaces[iPatch].m_nIndices];
  2635.  
  2636.             ASSERT(rgFaces[iPatch].m_aIndices,
  2637.                         "Could not allocate memory for patch indices");
  2638.  
  2639.             rgFaces[iPatch].m_aIndices[0]    = cCVsInV * (iCVIndexInU + 0) + (iCVIndexInV + 0);
  2640.             rgFaces[iPatch].m_aIndices[1]    = cCVsInV * (iCVIndexInU + 1) + (iCVIndexInV + 0);
  2641.             rgFaces[iPatch].m_aIndices[2]    = cCVsInV * (iCVIndexInU + 2) + (iCVIndexInV + 0);
  2642.  
  2643.             rgFaces[iPatch].m_aIndices[3]    = cCVsInV * (iCVIndexInU + 3) + (iCVIndexInV + 0);
  2644.             rgFaces[iPatch].m_aIndices[4]    = cCVsInV * (iCVIndexInU + 3) + (iCVIndexInV + 1);
  2645.             rgFaces[iPatch].m_aIndices[5]    = cCVsInV * (iCVIndexInU + 3) + (iCVIndexInV + 2);
  2646.  
  2647.             rgFaces[iPatch].m_aIndices[6]    = cCVsInV * (iCVIndexInU + 3) + (iCVIndexInV + 3);
  2648.             rgFaces[iPatch].m_aIndices[7]    = cCVsInV * (iCVIndexInU + 2) + (iCVIndexInV + 3);
  2649.             rgFaces[iPatch].m_aIndices[8]    = cCVsInV * (iCVIndexInU + 1) + (iCVIndexInV + 3);
  2650.  
  2651.             rgFaces[iPatch].m_aIndices[9]    = cCVsInV * (iCVIndexInU + 0) + (iCVIndexInV + 3);
  2652.             rgFaces[iPatch].m_aIndices[10]    = cCVsInV * (iCVIndexInU + 0) + (iCVIndexInV + 2);
  2653.             rgFaces[iPatch].m_aIndices[11]    = cCVsInV * (iCVIndexInU + 0) + (iCVIndexInV + 1);
  2654.  
  2655.             rgFaces[iPatch].m_aIndices[12]    = cCVsInV * (iCVIndexInU + 1) + (iCVIndexInV + 1);
  2656.             rgFaces[iPatch].m_aIndices[13]    = cCVsInV * (iCVIndexInU + 2) + (iCVIndexInV + 1);
  2657.  
  2658.             rgFaces[iPatch].m_aIndices[14]    = cCVsInV * (iCVIndexInU + 2) + (iCVIndexInV + 2);
  2659.             rgFaces[iPatch].m_aIndices[15]    = cCVsInV * (iCVIndexInU + 1) + (iCVIndexInV + 2);
  2660.  
  2661.             rgFaces[iPatch].m_iGroup        = 0;            //    WARNING: assumes only 1 material per surface
  2662.  
  2663.  
  2664.             cFaceIndices    += rgFaces[iPatch].m_nIndices;
  2665.         }
  2666.     }
  2667.  
  2668.  
  2669.  
  2670.     // material info
  2671.  
  2672.     cGroups        = DtGroupGetCount(iShape);
  2673.     rgGroups    = new SGroup[cGroups];
  2674.  
  2675.     ASSERT(rgGroups, 
  2676.                 "Can't allocate memory for material group array");
  2677.  
  2678.  
  2679.     ASSERT(cGroups == 1,
  2680.                 "Assumption was made that NURBS surfaces have only 1 material");
  2681.  
  2682.  
  2683.     for (UINT iGroup    = 0; iGroup < cGroups; iGroup++)
  2684.     {
  2685.  
  2686.         // material name
  2687.         DT_ATTEMPT(DtMtlGetName(iShape, iGroup, &rgGroups[iGroup].m_szMaterial));
  2688.  
  2689.         // texture file name
  2690.         DT_ATTEMPT(MyDtTextureGetFileName(rgGroups[iGroup].m_szMaterial, &rgGroups[iGroup].m_szTextureFile));
  2691.  
  2692.         // diffuse color 
  2693.         if (!rgGroups[iGroup].m_szTextureFile)
  2694.         {
  2695.             DT_ATTEMPT(DtMtlGetDiffuseClr(rgGroups[iGroup].m_szMaterial, 0, 
  2696.                                        &rgGroups[iGroup].m_fDiffuseRed, 
  2697.                                        &rgGroups[iGroup].m_fDiffuseGreen,
  2698.                                        &rgGroups[iGroup].m_fDiffuseBlue));
  2699.         }
  2700.         else     // material has a texture
  2701.         {
  2702.             //    load the diffuse factor into the diffuse components
  2703.  
  2704.             int        iMaterial;
  2705.  
  2706.             DT_ATTEMPT(DtMtlGetID(iShape, iGroup, &iMaterial));
  2707.  
  2708.             MObject    mShader;
  2709.  
  2710.             DT_ATTEMPT(DtExt_MtlGetShader(iMaterial, mShader));
  2711.  
  2712.             MFnLambertShader    fnShader;
  2713.  
  2714.             fnShader.setObject(mShader);
  2715.  
  2716.             float    fDiffuseFactor    = fnShader.diffuseCoeff();
  2717.  
  2718.             rgGroups[iGroup].m_fDiffuseRed    = fDiffuseFactor;
  2719.             rgGroups[iGroup].m_fDiffuseGreen    = fDiffuseFactor;
  2720.             rgGroups[iGroup].m_fDiffuseBlue    = fDiffuseFactor;
  2721.         }
  2722.  
  2723.         // specular color
  2724.         DT_ATTEMPT(DtMtlGetSpecularClr(rgGroups[iGroup].m_szMaterial, 0, 
  2725.                                     &rgGroups[iGroup].m_fSpecularRed, 
  2726.                                     &rgGroups[iGroup].m_fSpecularGreen, 
  2727.                                     &rgGroups[iGroup].m_fSpecularBlue));
  2728.  
  2729.         // emissive color
  2730.         DT_ATTEMPT(DtMtlGetEmissiveClr(rgGroups[iGroup].m_szMaterial, 0, 
  2731.                                     &rgGroups[iGroup].m_fEmissiveRed, 
  2732.                                     &rgGroups[iGroup].m_fEmissiveGreen, 
  2733.                                     &rgGroups[iGroup].m_fEmissiveBlue));
  2734.  
  2735.         // power / shininess
  2736.         DT_ATTEMPT(DtMtlGetShininess(rgGroups[iGroup].m_szMaterial, 0, &rgGroups[iGroup].m_fShininess));
  2737.  
  2738.         // transparency / alpha
  2739.         DT_ATTEMPT(DtMtlGetTransparency(rgGroups[iGroup].m_szMaterial, 0, &rgGroups[iGroup].m_fTransparency));
  2740.     }
  2741.     
  2742.  
  2743.  
  2744.  
  2745.  
  2746.     // vertex duplication info (very simple for patch meshes)
  2747.  
  2748.     cReps    = (int)rgCVs.length();
  2749.     rgReps    = new SRep[cReps];
  2750.  
  2751.     ASSERT(rgReps, 
  2752.                 "Can't allocate memory for rep array");
  2753.  
  2754.     for (UINT iRep = 0; iRep < cReps; iRep++) 
  2755.     {
  2756.         rgReps[iRep].m_iNorm    = -1;            // patches don't export normal info
  2757.         rgReps[iRep].m_iUV        = iRep;
  2758.         rgReps[iRep].m_iFirst    = iRep;
  2759.         rgReps[iRep].m_iNext    = iRep;
  2760.  
  2761.         rgReps[iRep].m_nReps    = 1;
  2762.     }
  2763.  
  2764.  
  2765.  
  2766.     // skinning info
  2767.             
  2768.  
  2769.     MObject    objShape;
  2770.     MObject objTransform;
  2771.     MObject    objInput;
  2772.  
  2773.     DT_ATTEMPT(DtExt_ShapeGetShapeNode(iShape, objShape));
  2774.     DT_ATTEMPT(DtExt_ShapeGetTransform(iShape, objTransform));
  2775.  
  2776.  
  2777.  
  2778.  
  2779.     // load the mesh's world transform (needed if skinning info is found)
  2780.     MDagPath    pathTransform;
  2781.  
  2782.     MFnDagNode(objTransform).getPath(pathTransform);
  2783.  
  2784.     MMatrix        matMeshWorldTransform    = pathTransform.inclusiveMatrix();
  2785.  
  2786.  
  2787.  
  2788.  
  2789.  
  2790.     cBones                = 0;
  2791.     rgBones                = NULL;
  2792.  
  2793.     cMaxBonesPerVertex    = 0;
  2794.     cMaxBonesPerFace    = 0;
  2795.  
  2796.  
  2797.     MObjectArray    rgobjBones;
  2798.  
  2799.  
  2800.  
  2801.  
  2802.  
  2803.  
  2804.  
  2805.     // smooth skinning
  2806.  
  2807.     bool*    rgbNonZeroFlagTable    = NULL;        // table of influences vs. vertices
  2808.     UINT*    rgcNonZeros            = NULL;        // array of influence counts 
  2809.  
  2810.     bool bFoundSmoothSkin    = false;
  2811.  
  2812.     if (objShape.hasFn(MFn::kNurbsSurface))         // if this shape is a mesh
  2813.     { 
  2814.         // loop through skin clusters
  2815.         for (MItDependencyNodes itSkin(MFn::kSkinClusterFilter); !itSkin.isDone(); itSkin.next()) 
  2816.         {
  2817.             MFnSkinCluster fnSkin(itSkin.item());
  2818.  
  2819.             // load input and output geometries
  2820.             MObjectArray    rgInputs;
  2821.             MObjectArray    rgOutputs;
  2822.  
  2823.             fnSkin.getInputGeometry(rgInputs);
  2824.             fnSkin.getOutputGeometry(rgOutputs);
  2825.  
  2826.             assert(rgInputs.length() == rgOutputs.length());        // ensure that input geometry count 
  2827.                                                                     // equals output geometry count
  2828.  
  2829.             int    cInputs, cOutputs;
  2830.  
  2831.             cInputs    = cOutputs    = (int)rgOutputs.length();
  2832.  
  2833.             // loop through the output geometries
  2834.             for (int iOutput = 0, iInput = 0; iOutput < cOutputs; iOutput++, iInput++) 
  2835.             {
  2836.                 assert(iOutput == iInput);        // sanity check
  2837.  
  2838.                 
  2839.                 if (rgOutputs[iOutput] == objShape)         // if our shape is one of the output geometries
  2840.                 {
  2841.                     MDagPathArray    rgdagpathInfluences;
  2842.                     
  2843.                     cBones    = (int)fnSkin.influenceObjects(rgdagpathInfluences, &mStat);
  2844.  
  2845.                     rgBones    = new SBone[cBones];
  2846.  
  2847.                     ASSERT(rgBones,
  2848.                                 "Could not allocate memory for bone array");
  2849.  
  2850.  
  2851.                     // initialize bones
  2852.                     for (UINT iBone = 0; iBone < cBones; iBone++) 
  2853.                     {    // WARNING: not checking for new failure
  2854.                         rgBones[iBone].m_szName            = new char[256];
  2855.                         rgBones[iBone].m_nReps            = 0;
  2856.                         rgBones[iBone].m_nWeights        = 0;
  2857.                         rgBones[iBone].m_aiPoints    = new int[cVertices];
  2858.                         rgBones[iBone].m_afWeights        = new float[cVertices];
  2859.  
  2860.                         g_Strings.add(rgBones[iBone].m_szName);        // housekeeping
  2861.  
  2862.                         // bone name
  2863.                         strcpy(rgBones[iBone].m_szName, rgdagpathInfluences[iBone].partialPathName().asChar());
  2864.  
  2865.                         // matrix offset
  2866.                         MFnIkJoint fnBone(rgdagpathInfluences[iBone]);
  2867.  
  2868.                         MObject objBindPose;
  2869.  
  2870.                         fnBone.findPlug("bindPose").getValue(objBindPose);
  2871.  
  2872.                         MFnMatrixData fnBindPose(objBindPose);
  2873.  
  2874.                         (matMeshWorldTransform * fnBindPose.matrix().inverse()).get(rgBones[iBone].m_matOffset);
  2875.  
  2876.  
  2877.  
  2878.                         rgobjBones.append(rgdagpathInfluences[iBone].node());
  2879.                     }
  2880.  
  2881.                     rgcNonZeros            = new UINT[cVertices];
  2882.  
  2883.                     ASSERT(rgcNonZeros,
  2884.                                 "Could not allocate memory for non zero count array");
  2885.  
  2886.                     rgbNonZeroFlagTable    = new bool[cVertices * cBones];
  2887.  
  2888.                     ASSERT(rgbNonZeroFlagTable,
  2889.                                 "Could not allocate memory for non zero table");
  2890.  
  2891.                     // bone info; calculate max number of bones per vertex
  2892.                     cMaxBonesPerVertex = 0;
  2893.  
  2894.                     int iVertex = 0;
  2895.  
  2896.                     MFnNurbsSurface fnOutput(rgOutputs[iOutput]);
  2897.  
  2898.                     MDagPath dagpathOutputShape;
  2899.                 
  2900.                     fnOutput.getPath(dagpathOutputShape);
  2901.  
  2902.                     // loop through the vertices
  2903.                     for (MItGeometry itGeom(rgOutputs[iOutput]); !itGeom.isDone(); itGeom.next()) 
  2904.                     {
  2905.     
  2906.                         MFloatArray rgfWeights;
  2907.  
  2908.                         unsigned cInfs;
  2909.  
  2910.                         fnSkin.getWeights(dagpathOutputShape, itGeom.component(), rgfWeights, cInfs);
  2911.  
  2912.                         int a = rgdagpathInfluences.length();
  2913.                         int b = rgfWeights.length();
  2914.                         int c = itGeom.count();
  2915.  
  2916.                         assert(rgdagpathInfluences.length() == rgfWeights.length());
  2917.                         assert(rgfWeights.length() == cInfs);
  2918.  
  2919.                         rgcNonZeros[iVertex] = 0;
  2920.  
  2921.  
  2922.                         float fWeightSum = 0.0f;
  2923.  
  2924.                         for (UINT iBone = 0; iBone < cBones; iBone++)
  2925.                             fWeightSum += rgfWeights[iBone];
  2926.  
  2927.                         assert(fWeightSum > 0.00001f);
  2928.  
  2929.                         for (iBone = 0; iBone < cBones; iBone++) 
  2930.                         {
  2931.                             rgbNonZeroFlagTable[iBone * cVertices + iVertex]    = false;
  2932.  
  2933.                             rgfWeights[iBone] = rgfWeights[iBone] / fWeightSum;        // normalize the weight
  2934.  
  2935.                             if (rgfWeights[iBone] != 0.0f) 
  2936.                             {
  2937.                                 rgcNonZeros[iVertex]++;
  2938.  
  2939.                                 rgBones[iBone].m_nReps += rgReps[iVertex].m_nReps;
  2940.         
  2941.                                 rgBones[iBone].m_aiPoints[rgBones[iBone].m_nWeights]    = iVertex;                            
  2942.                                 rgBones[iBone].m_afWeights[rgBones[iBone].m_nWeights]    = rgfWeights[iBone];
  2943.  
  2944.                                 rgbNonZeroFlagTable[iBone * cVertices + iVertex]    = true;
  2945.  
  2946.                                 rgBones[iBone].m_nWeights++;
  2947.                             }
  2948.                         }
  2949.  
  2950.  
  2951.                         if (rgcNonZeros[iVertex] > cMaxBonesPerVertex)
  2952.                             cMaxBonesPerVertex = rgcNonZeros[iVertex];
  2953.  
  2954.                         iVertex++;
  2955.                     }
  2956.  
  2957.  
  2958.  
  2959.                     // calculate max number of bones per vertex
  2960.  
  2961.                     cMaxBonesPerFace    = 0;
  2962.  
  2963.                     for (UINT iFace = 0; iFace < cFaces; iFace++) 
  2964.                     {
  2965.                         UINT    cBonesPerFace    = 0;
  2966.  
  2967.                         for (UINT iBone = 0; iBone < cBones; iBone++) 
  2968.                         {
  2969.                             for (UINT iIndex = 0; iIndex < rgFaces[iFace].m_nIndices; iIndex++) 
  2970.                             {
  2971.                                 if (rgbNonZeroFlagTable[iBone * cVertices + rgReps[rgFaces[iFace].m_aIndices[iIndex]].m_iFirst]) 
  2972.                                 {
  2973.                                     cBonesPerFace++;
  2974.  
  2975.                                     break;
  2976.                                 }
  2977.                             }
  2978.                         }
  2979.  
  2980.                         if (cBonesPerFace > cMaxBonesPerFace)
  2981.                             cMaxBonesPerFace = cBonesPerFace;
  2982.                     }
  2983.  
  2984.  
  2985.  
  2986.  
  2987.                     objInput = rgInputs[iInput];
  2988.  
  2989.                     bFoundSmoothSkin = true;
  2990.  
  2991.                     break;
  2992.                 }
  2993.             }
  2994.  
  2995.             if (bFoundSmoothSkin)
  2996.                 break;
  2997.         }
  2998.     }
  2999.  
  3000.  
  3001.     delete[] rgcNonZeros;
  3002.     delete[] rgbNonZeroFlagTable;
  3003.  
  3004.  
  3005.  
  3006.  
  3007.  
  3008.  
  3009.  
  3010.  
  3011.  
  3012.  
  3013.  
  3014.  
  3015.  
  3016.  
  3017.  
  3018.  
  3019.  
  3020.  
  3021.  
  3022.     // rigid skinning
  3023.  
  3024.     rgbNonZeroFlagTable    = NULL;
  3025.  
  3026.     bool    bFoundRigidSkin    = false;
  3027.  
  3028.     if (!bFoundSmoothSkin)     
  3029.     {
  3030.         cBones            = 1;                        // zero'th bone is the extra "fake" bone
  3031.         UINT cBonesMax    = 64;
  3032.         rgBones            = new SBone[cBonesMax];
  3033.  
  3034.         ASSERT(rgBones,
  3035.                     "Could not allocate memory for bone array");
  3036.  
  3037.         rgbNonZeroFlagTable    = new bool[cBonesMax * cVertices];
  3038.  
  3039.         ASSERT(rgbNonZeroFlagTable,
  3040.                     "Could not allocate memory for non-zero flag table");
  3041.  
  3042.         // fill non zero table with 0's
  3043.         memset(rgbNonZeroFlagTable, 0, cBonesMax * cVertices * sizeof(bool));
  3044.  
  3045.         // initialize "fake" iBone
  3046.         // WARNING: not checking for new failure
  3047.         rgBones[0].m_szName            = new char[256];
  3048.         rgBones[0].m_nReps            = 0;
  3049.         rgBones[0].m_nWeights        = 0;
  3050.         rgBones[0].m_afWeights        = new float[cVertices];
  3051.         rgBones[0].m_aiPoints    = new int[cVertices];
  3052.  
  3053.         g_Strings.add(rgBones[0].m_szName);                            // housekeeping
  3054.  
  3055.         strcpy(rgBones[0].m_szName, SCENE_ROOT);                    // bone name
  3056.     
  3057.         matMeshWorldTransform.get(rgBones[0].m_matOffset);            // "fake" bone has identity matrix
  3058.  
  3059.  
  3060.         // loop through joint clusters
  3061.         for (MItDependencyNodes itCluster(MFn::kJointCluster); !itCluster.isDone(); itCluster.next()) 
  3062.         {
  3063.             MFnWeightGeometryFilter fnCluster(itCluster.item());
  3064.  
  3065.             // load input and output geometries
  3066.             MObjectArray    rgInputs;
  3067.             MObjectArray    rgOutputs;
  3068.  
  3069.             fnCluster.getInputGeometry(rgInputs);
  3070.             fnCluster.getOutputGeometry(rgOutputs);
  3071.  
  3072.             assert(rgInputs.length() == rgOutputs.length());    // ensure input geometry count equals 
  3073.                                                                 // output geometry count
  3074.  
  3075.             int    cInputs, cOutputs;
  3076.  
  3077.             cInputs    = cOutputs    
  3078.                 = (int)rgOutputs.length();
  3079.  
  3080.             // loop through the output geometries
  3081.             for (int iOutput = 0, iInput = 0; iOutput < cOutputs; iOutput++, iInput++) 
  3082.             {
  3083.                 assert(iOutput == iInput);
  3084.                 
  3085.                 if (rgOutputs[iOutput] == objShape)     // our shape is one of the output geometries
  3086.                 {
  3087.                     bFoundRigidSkin    = true;
  3088.         
  3089.                     assert(rgInputs[iInput] == fnCluster.inputShapeAtIndex(iInput));    // sanity check
  3090.  
  3091.                     objInput    = rgInputs[iInput];
  3092.  
  3093.                     // get bone
  3094.                     MPlug        plgMatrix    = fnCluster.findPlug("matrix", &mStat);
  3095.  
  3096.                     MPlugArray    rgplgMatrixConnections;
  3097.  
  3098.                     plgMatrix.connectedTo(rgplgMatrixConnections, true, false);            // get source plugs
  3099.                     assert(rgplgMatrixConnections.length() == 1);
  3100.  
  3101.                     MObject    objBone    = rgplgMatrixConnections[0].node();
  3102.  
  3103.                     assert(objBone.hasFn(MFn::kJoint));
  3104.  
  3105.                     MFnIkJoint fnBone(objBone);
  3106.  
  3107.                     char    szBone[64];
  3108.  
  3109.                     strcpy(szBone, fnBone.name().asChar());
  3110.  
  3111.                     // find bone's index in current bone list
  3112.                     for (UINT iBone = 1; iBone < cBones;    iBone++) 
  3113.                     {
  3114.                         if (!strcmp(rgBones[iBone].m_szName, szBone))
  3115.                             break;
  3116.                     }
  3117.     
  3118.                     if (iBone == cBones)     // bone was not found in current bone list
  3119.                     {
  3120.                         // add bone
  3121.                         if (cBones >= cBonesMax) 
  3122.                         {
  3123.                             // double array size
  3124.                             cBonesMax  += cBonesMax;
  3125.  
  3126.                             SBone*    rgNewBones    = new SBone[cBonesMax];
  3127.  
  3128.                             ASSERT(rgNewBones, 
  3129.                                         "Could not allocate memory for new bone array");
  3130.  
  3131.                             memcpy(rgNewBones, rgBones, cBones * sizeof(SBone));
  3132.  
  3133.                             delete[] rgBones;
  3134.  
  3135.                             rgBones    = rgNewBones;
  3136.  
  3137.  
  3138.                             bool*    rgbNewNonZeroFlagTable    = new bool[cBonesMax * cVertices];
  3139.  
  3140.                             ASSERT(rgbNewNonZeroFlagTable, 
  3141.                                         "Could not allocate memory for new non-zero flag table");
  3142.  
  3143.                             memset(rgbNewNonZeroFlagTable, 0, cBonesMax * cVertices * sizeof(bool));
  3144.                             memcpy(rgbNewNonZeroFlagTable, rgbNonZeroFlagTable, cBones * cVertices * sizeof(bool));
  3145.  
  3146.                             delete[] rgbNonZeroFlagTable;
  3147.  
  3148.                             rgbNonZeroFlagTable    = rgbNewNonZeroFlagTable;
  3149.                         }
  3150.         
  3151.                         // initialize iBone
  3152.                         // WARNING: not checking for new failure
  3153.                         rgBones[iBone].m_szName            = new char[256];
  3154.                         rgBones[iBone].m_nReps            = 0;
  3155.                         rgBones[iBone].m_nWeights        = 0;
  3156.                         rgBones[iBone].m_aiPoints    = new int[cVertices];
  3157.                         rgBones[iBone].m_afWeights        = new float[cVertices];
  3158.  
  3159.                         g_Strings.add(rgBones[iBone].m_szName);                            // housekeeping
  3160.  
  3161.                         strcpy(rgBones[iBone].m_szName, szBone);                        // bone name
  3162.     
  3163.                         // matrix info
  3164.                         MObject objBindPose;
  3165.  
  3166.                         fnBone.findPlug("bindPose").getValue(objBindPose);
  3167.  
  3168.                         MFnMatrixData fnBindPose(objBindPose);
  3169.  
  3170.                         (matMeshWorldTransform * fnBindPose.matrix().inverse()).get(rgBones[iBone].m_matOffset);
  3171.  
  3172.  
  3173.                         rgobjBones.append(objBone);
  3174.  
  3175.                         cBones++;
  3176.                     }
  3177.  
  3178.  
  3179.  
  3180.                     char    szParent[64];
  3181.  
  3182.                     bool    bFoundParent    = false;
  3183.                     MObject    objParent; 
  3184.  
  3185.                     for (UINT iParent = 0; iParent < fnBone.parentCount(); iParent++) 
  3186.                     {
  3187.                         objParent    = fnBone.parent(iParent);
  3188.  
  3189.                         MFnDagNode    fnParent(objParent);
  3190.                         
  3191.                         strcpy(szParent, fnParent.name().asChar());        // parent's name
  3192.  
  3193.                         for (int iShape_ = 0; iShape_ < DtShapeGetCount(); iShape_++) 
  3194.                         {
  3195.                             char*    szShape;
  3196.  
  3197.                             DT_ATTEMPT(DtShapeGetName(iShape_, &szShape));
  3198.  
  3199.                             if (!strcmp(szParent, szShape)) 
  3200.                             {
  3201.                                 bFoundParent    = true;
  3202.  
  3203.                                 break;
  3204.                             }
  3205.                         }
  3206.  
  3207.                         if (bFoundParent)
  3208.                             break;
  3209.                     }
  3210.   
  3211.                     iParent    = 0;
  3212.  
  3213.                     if (bFoundParent)     // parent shape found
  3214.                     {
  3215.                         // find parent bone's index in current bone list
  3216.                         for (iParent = 1; iParent < cBones;    iParent++) 
  3217.                         {
  3218.                             if (!strcmp(rgBones[iParent].m_szName, szParent)) 
  3219.                             {
  3220.                                 break;
  3221.                             }
  3222.                         }
  3223.  
  3224.  
  3225.                         if (iParent == cBones)         // parent bone was not found in current bone list
  3226.                         {
  3227.                             // add parent bone
  3228.                             if (cBones >= cBonesMax) 
  3229.                             {
  3230.                                 // double array size
  3231.                                 cBonesMax  += cBonesMax;
  3232.  
  3233.                                 SBone*    rgNewBones    = new SBone[cBonesMax];
  3234.  
  3235.                                 ASSERT(rgNewBones, 
  3236.                                             "Could not allocate memory for new bone array");
  3237.     
  3238.                                 memcpy(rgNewBones, rgBones, cBones * sizeof(SBone));
  3239.     
  3240.                                 delete[] rgBones;
  3241.  
  3242.                                 rgBones    = rgNewBones;
  3243.  
  3244.                                 
  3245.                                 bool*    rgbNewNonZeroFlagTable    = new bool[cBonesMax * cVertices];
  3246.  
  3247.                                 ASSERT(rgbNewNonZeroFlagTable, 
  3248.                                             "Could not allocate memory for new non-zero flag table");
  3249.  
  3250.                                 memset(rgbNewNonZeroFlagTable, 0, cBonesMax * cVertices * sizeof(bool));
  3251.                                 memcpy(rgbNewNonZeroFlagTable, rgbNonZeroFlagTable, cBones * cVertices * sizeof(bool));
  3252.  
  3253.                                 delete[] rgbNonZeroFlagTable;
  3254.  
  3255.                                 rgbNonZeroFlagTable    = rgbNewNonZeroFlagTable;
  3256.                             }
  3257.             
  3258.                             // initialize iBone
  3259.                             // WARNING: not checking for new failure
  3260.                             rgBones[iParent].m_szName        = new char[256];
  3261.                             rgBones[iParent].m_nReps        = 0;
  3262.                             rgBones[iParent].m_nWeights        = 0;
  3263.                             rgBones[iParent].m_aiPoints    = new int[cVertices];
  3264.                             rgBones[iParent].m_afWeights    = new float[cVertices];
  3265.     
  3266.                             g_Strings.add(rgBones[iParent].m_szName);            // housekeeping
  3267.     
  3268.                             strcpy(rgBones[iParent].m_szName, szParent);        // bone name
  3269.  
  3270.                             // matrix info
  3271.                             MObject    objBindPose;
  3272.     
  3273.                             assert(objParent.hasFn(MFn::kJoint));
  3274.  
  3275.                             MFnIkJoint(objParent).findPlug("bindPose").getValue(objBindPose);
  3276.     
  3277.                             MFnMatrixData fnBindPose(objBindPose);
  3278.     
  3279.                             (matMeshWorldTransform * fnBindPose.matrix().inverse()).get(rgBones[iParent].m_matOffset);
  3280.  
  3281.  
  3282.                             rgobjBones.append(objParent);
  3283.  
  3284.                             cBones++;
  3285.                         }
  3286.                     }
  3287.  
  3288.  
  3289.                     // load weights
  3290.                     MPlug        plgMessage    = fnCluster.findPlug("message");
  3291.  
  3292.                     MPlugArray    rgplgMessageConnections;
  3293.  
  3294.                     plgMessage.connectedTo(rgplgMessageConnections, false, true);    // get destination plugs
  3295.  
  3296.                     assert(rgplgMessageConnections.length() == 1);
  3297.                     assert(rgplgMessageConnections[0].node().hasFn(MFn::kSet));
  3298.  
  3299.                     MFnSet fnSet(rgplgMessageConnections[0].node());
  3300.                 
  3301.                     MSelectionList list;
  3302.  
  3303.                     fnSet.getMembers(list, false);
  3304.  
  3305.                     assert(list.length() == 1);
  3306.  
  3307.                     MDagPath    path;
  3308.                     MObject        objComponents;
  3309.  
  3310.                     list.getDagPath(0, path, objComponents);
  3311.  
  3312.                     MFloatArray    rgWeights;
  3313.  
  3314.                     fnCluster.getWeights(path, objComponents, rgWeights);
  3315.  
  3316.                     assert(objComponents.hasFn(MFn::kDoubleIndexedComponent));
  3317.  
  3318.  
  3319.                     MFnDoubleIndexedComponent fnComponent(objComponents);
  3320.  
  3321.                     assert(fnComponent.elementCount() == (int)rgWeights.length());
  3322.  
  3323.                     // loop through the weights
  3324.                     for (int iWeight = 0; iWeight < (int)rgWeights.length(); iWeight++) 
  3325.                     {
  3326.                         assert(rgWeights[iWeight] <= 1.0f);
  3327.  
  3328.                         int    iU, iV;
  3329.  
  3330.                         fnComponent.getElement(iWeight, iU, iV);
  3331.  
  3332.                         // WARNING: check calculation of iVertex
  3333.                         int    iVertex    = iU * cCVsInV + iV;
  3334.                         
  3335.                         rgBones[iBone].m_afWeights[rgBones[iBone].m_nWeights]    = rgWeights[iWeight];
  3336.                         rgBones[iBone].m_aiPoints[rgBones[iBone].m_nWeights]    = iVertex;
  3337.  
  3338.                         rgBones[iBone].m_nReps     += rgReps[iVertex].m_nReps;
  3339.                         rgBones[iBone].m_nWeights++;
  3340.  
  3341.                         rgbNonZeroFlagTable[iBone * cVertices + iVertex]    = true;
  3342.  
  3343.                         if (rgWeights[iWeight] != 1.0f) 
  3344.                         {
  3345.                             rgBones[iParent].m_afWeights[rgBones[iParent].m_nWeights]    = 1.0f - rgWeights[iWeight];
  3346.                             rgBones[iParent].m_aiPoints[rgBones[iParent].m_nWeights]    = iVertex;
  3347.  
  3348.                             rgBones[iParent].m_nReps   += rgReps[iVertex].m_nReps;
  3349.                             rgBones[iParent].m_nWeights++;                // IMPORTANT: Don't change line position
  3350.  
  3351.                             rgbNonZeroFlagTable[iParent * cVertices + iVertex]    = true;
  3352.                         }
  3353.                     }
  3354.  
  3355.                     break;
  3356.                 }    // if found our mesh
  3357.             }    // loop thru geom's
  3358.         }    // loop thru joint clusters
  3359.  
  3360.  
  3361.         if (cBones == 1)         // no rigid skinning found
  3362.         {
  3363.             delete[] rgBones[0].m_afWeights;
  3364.             delete[] rgBones[0].m_aiPoints;
  3365.  
  3366.             cBones    = 0;
  3367.         }
  3368.         else 
  3369.         {
  3370.             // at most 2 bones per vertex in rigid skinning (i.e. bone + parent)
  3371.             cMaxBonesPerVertex    = 2;
  3372.  
  3373.             // calculate max number of bones per vertex
  3374.             cMaxBonesPerFace    = 0;
  3375.  
  3376.             for (UINT iFace = 0; iFace < cFaces; iFace++) 
  3377.             {
  3378.                 UINT    cBonesPerFace    = 0;
  3379.  
  3380.                 for (UINT iBone = 0; iBone < cBones; iBone++) 
  3381.                 {
  3382.                     for (UINT iIndex = 0; iIndex < rgFaces[iFace].m_nIndices; iIndex++) 
  3383.                     {
  3384.                         if (rgbNonZeroFlagTable[iBone * cVertices + rgReps[rgFaces[iFace].m_aIndices[iIndex]].m_iFirst]) 
  3385.                         {
  3386.                             cBonesPerFace++;
  3387.  
  3388.                             break;
  3389.                         }
  3390.                     }
  3391.                 }
  3392.  
  3393.                 if (cBonesPerFace > cMaxBonesPerFace)
  3394.                     cMaxBonesPerFace = cBonesPerFace;
  3395.             }
  3396.             
  3397.         }
  3398.     }
  3399.                 
  3400.                 
  3401.     delete[] rgbNonZeroFlagTable;
  3402.  
  3403.  
  3404.  
  3405.  
  3406.  
  3407.  
  3408.  
  3409.  
  3410.  
  3411.  
  3412.  
  3413.  
  3414.  
  3415.  
  3416.  
  3417.  
  3418.  
  3419.  
  3420.  
  3421.     // reload control vertices if skinning info was found
  3422.  
  3423.     if (bFoundSmoothSkin || bFoundRigidSkin)
  3424.     {
  3425.         delete[]    rgVertices;
  3426.  
  3427.         MyDtShapeGetControlPoints(objInput, objShape, &cVertices, &rgVertices);
  3428.     }
  3429.  
  3430.  
  3431.  
  3432.  
  3433.  
  3434.     // mesh type
  3435.     pShape->m_kType            = SMesh::PATCH_MESH;
  3436.  
  3437. */
  3438.  
  3439. e_Exit:
  3440.  
  3441.     return hr;    
  3442. }
  3443.  
  3444.  
  3445.  
  3446.  
  3447.  
  3448.  
  3449.  
  3450.  
  3451.  
  3452.  
  3453.  
  3454.  
  3455.  
  3456.  
  3457.  
  3458.  
  3459.  
  3460.  
  3461.  
  3462.  
  3463.  
  3464.  
  3465.  
  3466.  
  3467.  
  3468.  
  3469.  
  3470.  
  3471. HRESULT    AddSkin
  3472.         (
  3473.             SMesh*                    pShape, 
  3474.             LPDIRECTXFILEDATA        pShapeDataObject, 
  3475.             LPDIRECTXFILESAVEOBJECT    pxofSave
  3476.         ) 
  3477. {
  3478.     HRESULT    hr = S_OK;
  3479.  
  3480.     UINT iBone;
  3481.  
  3482.     LPDIRECTXFILEDATA pSkinDataObject = NULL;
  3483.     PBYTE pbSkinData = NULL;
  3484.  
  3485.  
  3486.     UINT cbSkinSize    = sizeof(WORD)        // nMaxSkinWeightsPerVertex
  3487.                     + sizeof(WORD)        // nMaxSkinWeightsPerFace
  3488.                     + sizeof(WORD);        // nBones
  3489.  
  3490.     PBYTE pbSkinCurr = pbSkinData = new BYTE[cbSkinSize];
  3491.  
  3492.     if (pbSkinData == NULL)
  3493.     {
  3494.         hr = E_OUTOFMEMORY;
  3495.         cout << "AddSkin(): Could not allocate memory for pbSkinData." << endl;
  3496.         goto e_Exit1;
  3497.     }
  3498.  
  3499.     // nMaxSkinWeightsPerVertex
  3500.     WRITE_WORD(pbSkinCurr, ((WORD)pShape->m_nMaxBonesPerPoint));
  3501.  
  3502.     // nMaxSkinWeightsPerFace
  3503.     WRITE_WORD(pbSkinCurr, ((WORD)pShape->m_nMaxBonesPerFace));
  3504.  
  3505.     // nBones
  3506.     WRITE_WORD(pbSkinCurr, ((WORD)pShape->m_nBones));
  3507.  
  3508.  
  3509.     hr = pxofSave->CreateDataObject(DXFILEOBJ_XSkinMeshHeader, NULL, NULL, cbSkinSize, pbSkinData, &pSkinDataObject);
  3510.     if (FAILED(hr))
  3511.     {
  3512.         cout <<    "AddSkin(): Could not create pSkinDataObject." << endl;
  3513.         goto e_Exit1;
  3514.     }
  3515.  
  3516.  
  3517.     hr = pShapeDataObject->AddDataObject(pSkinDataObject);
  3518.     if (FAILED(hr))
  3519.     {
  3520.         cout <<    "AddSkin(): Could not add pSkinDataObject to pShapeDataObject." << endl;
  3521.         goto e_Exit1;
  3522.     }
  3523.  
  3524.  
  3525. e_Exit1:
  3526.  
  3527.     delete[] pbSkinData;
  3528.  
  3529.     if (pSkinDataObject)
  3530.         pSkinDataObject->Release();
  3531.  
  3532.  
  3533.     if (FAILED(hr))
  3534.         return hr;
  3535.  
  3536.  
  3537.     // SkinWeights
  3538.     for (iBone = 0; iBone < pShape->m_nBones; iBone++) 
  3539.     {
  3540.         UINT iRow, iCol, iVertex;
  3541.         LPDIRECTXFILEDATA    pBoneDataObject    = NULL;
  3542.         PBYTE pbBoneData    = NULL;
  3543.         UINT cbBoneSize = sizeof(char*)                                    // transformNodeName
  3544.                         + sizeof(DWORD)                                    // nWeights
  3545.                         + sizeof(DWORD) * pShape->m_aBones[iBone].m_nReps    // vertexIndices[nWeights]
  3546.                         + sizeof(float) * pShape->m_aBones[iBone].m_nReps    // weights[nWeights]
  3547.                         + sizeof(float) * 16;                            // matrixOffset
  3548.  
  3549.         PBYTE pbBoneCurr = pbBoneData = new BYTE[cbBoneSize];
  3550.         if (pbBoneData == NULL)
  3551.         {
  3552.             hr = E_OUTOFMEMORY;
  3553.             cout << "AddSkin(): Could not allocate memory for pbBoneData." << endl;
  3554.             goto e_Exit2;
  3555.         }
  3556.  
  3557.         // transformNodeName
  3558.         WRITE_PCHAR(pbBoneCurr, ((char*)pShape->m_aBones[iBone].m_szName));
  3559.  
  3560.         // nWeights
  3561.         WRITE_DWORD(pbBoneCurr, ((DWORD)pShape->m_aBones[iBone].m_nReps));
  3562.  
  3563.         // vertexIndices[nWeights]
  3564.         for (iVertex = 0; iVertex < pShape->m_aBones[iBone].m_nWeights; iVertex++) 
  3565.         {
  3566.             UINT iRep = pShape->m_aBones[iBone].m_aiPoints[iVertex];
  3567.  
  3568.             do 
  3569.             {
  3570.                 WRITE_DWORD(pbBoneCurr, ((DWORD)iRep));
  3571.  
  3572.                 iRep = pShape->m_aReps[iRep].m_iNext;
  3573.             } while (iRep != pShape->m_aReps[iRep].m_iFirst);
  3574.         }
  3575.  
  3576.         // weights[nWeights]
  3577.         for (iVertex = 0; iVertex < pShape->m_aBones[iBone].m_nWeights; iVertex++)
  3578.         {
  3579.             for (UINT iRep = 0; iRep < pShape->m_aReps[pShape->m_aBones[iBone].m_aiPoints[iVertex]].m_nReps; iRep++)
  3580.             {
  3581.                 WRITE_FLOAT(pbBoneCurr, pShape->m_aBones[iBone].m_afWeights[iVertex]);
  3582.             }
  3583.         }
  3584.  
  3585.         // matrixOffset
  3586.         for (iRow = 0; iRow < 4; iRow++)
  3587.         {
  3588.             for (iCol = 0; iCol < 4; iCol++)
  3589.             {
  3590.                 WRITE_FLOAT(pbBoneCurr, pShape->m_aBones[iBone].m_aafOffset[iRow][iCol]);
  3591.             }
  3592.         }
  3593.  
  3594.  
  3595.         hr = pxofSave->CreateDataObject(DXFILEOBJ_SkinWeights, NULL, NULL, cbBoneSize, pbBoneData, &pBoneDataObject);
  3596.         if (FAILED(hr))
  3597.         {
  3598.             cout << "AddSkin(): Could not create pBoneDataObject." << endl;
  3599.             goto e_Exit2;
  3600.         }
  3601.  
  3602.  
  3603.         hr = pShapeDataObject->AddDataObject(pBoneDataObject);
  3604.         if (FAILED(hr))
  3605.         {
  3606.             cout << "AddSkin(): Could not add pBoneDataObject to pShapeDataObject." << endl;
  3607.             goto e_Exit2;
  3608.         }
  3609.  
  3610.  
  3611.  
  3612. e_Exit2:
  3613.  
  3614.         delete[] pbBoneData;
  3615.  
  3616.         if (pBoneDataObject)
  3617.             pBoneDataObject->Release();
  3618.  
  3619.  
  3620.         if (FAILED(hr))
  3621.             return hr;
  3622.     }
  3623.  
  3624.  
  3625.     return hr;
  3626. }
  3627.  
  3628.  
  3629.  
  3630.  
  3631.  
  3632.  
  3633.  
  3634.  
  3635.  
  3636.  
  3637. HRESULT    AddNormals
  3638.         (
  3639.             SMesh*                    pShape, 
  3640.             LPDIRECTXFILEDATA        pShapeDataObject, 
  3641.             LPDIRECTXFILESAVEOBJECT pxofSave
  3642.         ) 
  3643. {
  3644.     HRESULT    hr    = S_OK;
  3645.  
  3646.     LPDIRECTXFILEDATA    pNormalsDataObject    = NULL;
  3647.  
  3648.     PBYTE    pbNormalsData    = NULL;
  3649.  
  3650.     int        cbNormalsSize    = sizeof(DWORD)                                                    // nNormals
  3651.                             + pShape->m_nReps * (3 * sizeof(float))                            // normals
  3652.                             + sizeof(DWORD)                                                    // nFaceNormals
  3653.                             + (pShape->m_nFaces + pShape->m_nFaceIndices) * sizeof(DWORD);    // faceNormals
  3654.  
  3655.     PBYTE    pbNormalsCurr    = pbNormalsData    
  3656.                             = new BYTE[cbNormalsSize];
  3657.  
  3658.     if (pbNormalsData == NULL)
  3659.     {
  3660.         hr = E_OUTOFMEMORY;
  3661.         cout << "AddNormals(): Could not allocate memory for pbNormalsData." << endl;
  3662.         goto e_Exit;
  3663.     }
  3664.  
  3665.  
  3666.     // nNormals
  3667.     WRITE_DWORD(pbNormalsCurr, ((DWORD)pShape->m_nReps));
  3668.  
  3669.     // normals
  3670.     UINT iRep;
  3671.  
  3672.     for (iRep = 0; iRep < pShape->m_nReps; iRep++) 
  3673.     {
  3674.         if (pShape->m_aReps[iRep].m_iNorm == -1)        // no normal index found
  3675.         {
  3676.             WRITE_FLOAT(pbNormalsCurr, 1.0f);
  3677.             WRITE_FLOAT(pbNormalsCurr, 0.0f);
  3678.             WRITE_FLOAT(pbNormalsCurr, 0.0f);
  3679.         }
  3680.         else 
  3681.         {
  3682.             WRITE_FLOAT(pbNormalsCurr, pShape->m_aNormals[pShape->m_aReps[iRep].m_iNorm].vec[0]);
  3683.             WRITE_FLOAT(pbNormalsCurr, pShape->m_aNormals[pShape->m_aReps[iRep].m_iNorm].vec[1]);
  3684.             WRITE_FLOAT(pbNormalsCurr, pShape->m_aNormals[pShape->m_aReps[iRep].m_iNorm].vec[2]);
  3685.         }
  3686.     }
  3687.  
  3688.     // nFaceNormals
  3689.     WRITE_DWORD(pbNormalsCurr, ((DWORD)pShape->m_nFaces));
  3690.  
  3691.     // faceNormals
  3692.     UINT iFace;
  3693.  
  3694.     for (iFace = 0; iFace < pShape->m_nFaces; iFace++) 
  3695.     {
  3696.         WRITE_DWORD(pbNormalsCurr, ((DWORD)pShape->m_aFaces[iFace].m_nIndices));
  3697.  
  3698.         for (UINT iIndex = 0; iIndex < pShape->m_aFaces[iFace].m_nIndices; iIndex++)
  3699.             WRITE_DWORD(pbNormalsCurr, ((DWORD)pShape->m_aFaces[iFace].m_aIndices[iIndex]));
  3700.     }
  3701.  
  3702.  
  3703.     hr = pxofSave->CreateDataObject(TID_D3DRMMeshNormals, NULL, NULL, cbNormalsSize, pbNormalsData, &pNormalsDataObject);
  3704.     if (FAILED(hr)) 
  3705.     {
  3706.         cout << "AddNormals(): Could not create normals data object." << endl;
  3707.         goto e_Exit;
  3708.     }
  3709.  
  3710.  
  3711.  
  3712.     hr = pShapeDataObject->AddDataObject(pNormalsDataObject);
  3713.     if (FAILED(hr)) 
  3714.     {
  3715.         cout << "AddNormals(): Could not add pNormalsDataObject to pShapeDataObject." << endl;
  3716.         goto e_Exit;
  3717.     }
  3718.  
  3719. e_Exit:
  3720.     // clean up
  3721.     delete[] pbNormalsData;
  3722.  
  3723.     if (pNormalsDataObject)
  3724.         pNormalsDataObject->Release();
  3725.  
  3726.     return hr;
  3727. }
  3728.  
  3729.  
  3730.  
  3731.  
  3732.  
  3733.  
  3734.  
  3735.  
  3736.  
  3737.  
  3738. HRESULT    AddTexCoords
  3739.         (
  3740.             SMesh*                    pShape, 
  3741.             LPDIRECTXFILEDATA        pShapeDataObject, 
  3742.             LPDIRECTXFILESAVEOBJECT    pxofSave
  3743.         ) 
  3744. {
  3745.     HRESULT    hr    = S_OK;
  3746.     UINT iRep;
  3747.     LPDIRECTXFILEDATA pTexCoordsDataObject = NULL;
  3748.     PBYTE pbTexCoordsData = NULL;
  3749.  
  3750.     int cbTexCoordsSize    = sizeof(DWORD)                            // nTextureCoords
  3751.                         + pShape->m_nReps * (2 * sizeof(float));    // textureCoords
  3752.  
  3753.     PBYTE pbTexCoordsCurr = pbTexCoordsData = new BYTE[cbTexCoordsSize];
  3754.  
  3755.     if (pbTexCoordsData == NULL)
  3756.     {
  3757.         hr = E_OUTOFMEMORY;
  3758.         cout << "AddTexCoords(): Could not allocate memory for pbTexCoordsData." << endl;
  3759.         goto e_Exit;
  3760.     }
  3761.  
  3762.  
  3763.     // nTextureCoords
  3764.     WRITE_DWORD(pbTexCoordsCurr, ((DWORD)pShape->m_nReps));
  3765.  
  3766.     // textureCoords
  3767.     for (iRep = 0; iRep < pShape->m_nReps; iRep++) 
  3768.     {
  3769.         if (pShape->m_aReps[iRep].m_iUV == -1)
  3770.         {
  3771.             WRITE_FLOAT(pbTexCoordsCurr, 0.0f);
  3772.             WRITE_FLOAT(pbTexCoordsCurr, 0.0f);
  3773.         }
  3774.         else 
  3775.         {
  3776.             WRITE_FLOAT(pbTexCoordsCurr, g_iFlipU * pShape->m_aUVs[pShape->m_aReps[iRep].m_iUV].vec[0]);
  3777.             WRITE_FLOAT(pbTexCoordsCurr, g_iFlipV * pShape->m_aUVs[pShape->m_aReps[iRep].m_iUV].vec[1]);
  3778.         }
  3779.     }
  3780.  
  3781.     hr = pxofSave->CreateDataObject(TID_D3DRMMeshTextureCoords, NULL, NULL, cbTexCoordsSize, pbTexCoordsData, &pTexCoordsDataObject);
  3782.     if (FAILED(hr))
  3783.     {
  3784.         cout << "AddTexCoords(): Could not create pTexCoordsDataObject." << endl;
  3785.         goto e_Exit;
  3786.     }
  3787.  
  3788.  
  3789.     hr = pShapeDataObject->AddDataObject(pTexCoordsDataObject);
  3790.     if (FAILED(hr))
  3791.     {
  3792.         cout << "AddTexCoords(): Could not add data object." << endl;
  3793.         goto e_Exit;
  3794.     }
  3795.  
  3796.  
  3797. e_Exit:
  3798.     delete[] pbTexCoordsData;
  3799.  
  3800.     if (pTexCoordsDataObject)
  3801.         pTexCoordsDataObject->Release();
  3802.  
  3803.     return hr;
  3804. }
  3805.  
  3806.  
  3807.  
  3808.  
  3809.  
  3810.  
  3811.  
  3812. HRESULT    AddMaterialList
  3813.         (
  3814.             SMesh*                    pShape, 
  3815.             LPDIRECTXFILEDATA        pShapeDataObject, 
  3816.             LPDIRECTXFILESAVEOBJECT    pxofSave
  3817.         ) 
  3818. {
  3819.     HRESULT    hr = S_OK;
  3820.     UINT iGroup, iFace;
  3821.     LPDIRECTXFILEDATA pMaterialsDataObject = NULL;
  3822.     PBYTE pbMaterialsData = NULL;
  3823.     
  3824.     int cbMaterialsSize    = sizeof(DWORD)                        // nMaterials
  3825.                         + sizeof(DWORD)                        // nFaceIndexes
  3826.                         + pShape->m_nFaces * sizeof(DWORD);    // FaceIndexes
  3827.  
  3828.     PBYTE    pbMaterialsCurr    = pbMaterialsData    = new BYTE[cbMaterialsSize];
  3829.  
  3830.     if (pbMaterialsCurr == NULL)
  3831.     {
  3832.         hr = E_OUTOFMEMORY;
  3833.         cout << "AddMaterialList(): Could not allocate memory for pbMaterialsData." << endl;
  3834.         goto e_Exit;
  3835.     }
  3836.  
  3837.  
  3838.     // nMaterials
  3839.     WRITE_DWORD(pbMaterialsCurr, ((DWORD)pShape->m_nGroups));
  3840.  
  3841.     // nFaceIndexes
  3842.     WRITE_DWORD(pbMaterialsCurr, ((DWORD)pShape->m_nFaces));
  3843.  
  3844.     // FaceIndexes
  3845.     for (iFace = 0; iFace < pShape->m_nFaces; iFace++)
  3846.         WRITE_DWORD(pbMaterialsCurr, pShape->m_aFaces[iFace].m_iGroup);
  3847.  
  3848.  
  3849.     hr = pxofSave->CreateDataObject(TID_D3DRMMeshMaterialList, NULL, NULL, cbMaterialsSize, pbMaterialsData, &pMaterialsDataObject);
  3850.     if (FAILED(hr))
  3851.     {
  3852.         cout << "AddMaterialList(): Could not create pMaterialsDataObject." << endl;
  3853.         goto e_Exit;
  3854.     }
  3855.  
  3856.     // material data
  3857.     for (iGroup = 0; iGroup < pShape->m_nGroups; iGroup++) 
  3858.     {
  3859.         LPDIRECTXFILEDATA    pMaterialDataObject    = NULL;
  3860.         LPDIRECTXFILEDATA    pTextureDataObject    = NULL;
  3861.  
  3862.         PBYTE                pbMaterialData        = NULL;
  3863.  
  3864.         int cbMaterialSize = 4 * sizeof(float)        // faceColor
  3865.                             + sizeof(float)            // power
  3866.                             + 3 * sizeof(float)        // specularColor
  3867.                             + 3 * sizeof(float);    // emissiveColor
  3868.  
  3869.         PBYTE pbMaterialCurr = pbMaterialData = new BYTE[cbMaterialSize];
  3870.  
  3871.         if (pbMaterialData == NULL)
  3872.         {
  3873.             hr = E_OUTOFMEMORY;
  3874.             cout << "AddMaterialList(): Could not allocate memory for pbMaterialData." << endl;
  3875.             goto e_Exit2;
  3876.         }
  3877.  
  3878.  
  3879.         // faceColor
  3880.         WRITE_FLOAT(pbMaterialCurr, pShape->m_aGroups[iGroup].m_fDiffuseRed);
  3881.         WRITE_FLOAT(pbMaterialCurr, pShape->m_aGroups[iGroup].m_fDiffuseGreen);
  3882.         WRITE_FLOAT(pbMaterialCurr, pShape->m_aGroups[iGroup].m_fDiffuseBlue);
  3883.         WRITE_FLOAT(pbMaterialCurr, (1.0f - pShape->m_aGroups[iGroup].m_fTransparency));
  3884.  
  3885.         // power
  3886.         WRITE_FLOAT(pbMaterialCurr, pShape->m_aGroups[iGroup].m_fShininess);
  3887.         
  3888.         // specularColor
  3889.         WRITE_FLOAT(pbMaterialCurr, pShape->m_aGroups[iGroup].m_fSpecularRed);
  3890.         WRITE_FLOAT(pbMaterialCurr, pShape->m_aGroups[iGroup].m_fSpecularGreen);
  3891.         WRITE_FLOAT(pbMaterialCurr, pShape->m_aGroups[iGroup].m_fSpecularBlue);
  3892.  
  3893.         // emissiveColor
  3894.         WRITE_FLOAT(pbMaterialCurr, pShape->m_aGroups[iGroup].m_fEmissiveRed);
  3895.         WRITE_FLOAT(pbMaterialCurr, pShape->m_aGroups[iGroup].m_fEmissiveGreen);
  3896.         WRITE_FLOAT(pbMaterialCurr, pShape->m_aGroups[iGroup].m_fEmissiveBlue);
  3897.  
  3898.  
  3899.         hr = pxofSave->CreateDataObject(TID_D3DRMMaterial, pShape->m_aGroups[iGroup].m_szName, NULL, cbMaterialSize, pbMaterialData, &pMaterialDataObject);
  3900.         if (FAILED(hr))
  3901.         {
  3902.             cout << "AddMaterialList(): Could not create pMaterialDataObject." << endl;
  3903.             goto e_Exit2;
  3904.         }
  3905.  
  3906.  
  3907.         // TextureFilename        
  3908.         if (pShape->m_aGroups[iGroup].m_szTextureFile != NULL) 
  3909.         {
  3910.             int        cbTextureSize    = sizeof(char**);
  3911.  
  3912.             hr = pxofSave->CreateDataObject(TID_D3DRMTextureFilename, NULL, NULL, cbTextureSize, &pShape->m_aGroups[iGroup].m_szTextureFile, &pTextureDataObject);
  3913.             if (FAILED(hr))
  3914.             {
  3915.                 cout << "AddMaterialList(): Could not create pMaterialDataObject." << endl;
  3916.                 goto e_Exit2;
  3917.             }
  3918.  
  3919.             hr = pMaterialDataObject->AddDataObject(pTextureDataObject);
  3920.             if (FAILED(hr))
  3921.             {
  3922.                 cout << "AddMaterialList(): Could not add pTextureDataObject to pMaterialDataObject." << endl;
  3923.                 goto e_Exit2;
  3924.             }
  3925.         }
  3926.  
  3927.  
  3928.         hr = pMaterialsDataObject->AddDataObject(pMaterialDataObject);
  3929.         if (FAILED(hr))
  3930.         {
  3931.             cout << "AddMaterialList(): Could not add pMaterialDataObject to pMaterialsDataObject." << endl;
  3932.             goto e_Exit2;
  3933.         }
  3934.  
  3935.  
  3936. e_Exit2:
  3937.  
  3938.         delete[] pbMaterialData;
  3939.  
  3940.         if (pMaterialDataObject)
  3941.             pMaterialDataObject->Release();
  3942.  
  3943.         if (pTextureDataObject)
  3944.             pTextureDataObject->Release();
  3945.  
  3946.  
  3947.         if (FAILED(hr))
  3948.         {
  3949.             cout << "AddMaterialList(): Error occured while adding materials." << endl;
  3950.             goto e_Exit;
  3951.         }
  3952.     }
  3953.  
  3954.  
  3955.     hr = pShapeDataObject->AddDataObject(pMaterialsDataObject);
  3956.     if (FAILED(hr))
  3957.     {
  3958.         cout << "AddMaterialList(): Could not add pMaterialsDataObject to pShapeDataObject." << endl;
  3959.         goto e_Exit;
  3960.     }
  3961.  
  3962.  
  3963.  
  3964. e_Exit:
  3965.     delete[] pbMaterialsData;
  3966.  
  3967.     if (pMaterialsDataObject)
  3968.         pMaterialsDataObject->Release();    
  3969.     
  3970.         
  3971.     return hr;
  3972. }
  3973.  
  3974.  
  3975.  
  3976.  
  3977.  
  3978.  
  3979.  
  3980.  
  3981. HRESULT    AddVertexColors
  3982.         (
  3983.             SMesh*                    pShape, 
  3984.             LPDIRECTXFILEDATA        pShapeDataObject, 
  3985.             LPDIRECTXFILESAVEOBJECT    pxofSave
  3986.         ) 
  3987. {
  3988.     HRESULT    hr = S_OK;
  3989.     LPDIRECTXFILEDATA pColorsDataObject = NULL;
  3990.     PBYTE pbColorsData = NULL;
  3991.     UINT iRep;
  3992.     UINT cbColorsSize = sizeof(DWORD)                                                // nVertexColors
  3993.                         + pShape->m_nReps * (sizeof(DWORD) + 4 * sizeof(float));        // vertexColors
  3994.  
  3995.     PBYTE pbColorsCurr = pbColorsData = new BYTE[cbColorsSize];
  3996.     if (NULL == pbColorsData)
  3997.     {
  3998.         hr = E_OUTOFMEMORY;
  3999.         cout << "AddVertexColors(): Could not allocate memory for pbColorsData." << endl;
  4000.         goto e_Exit;
  4001.     }
  4002.  
  4003.  
  4004.     // nVertexColors
  4005.     WRITE_DWORD(pbColorsCurr, ((DWORD)pShape->m_nReps));
  4006.  
  4007.     // vertexColors
  4008.     for (iRep = 0; iRep < pShape->m_nReps; iRep++) 
  4009.     {
  4010.         // index
  4011.         WRITE_DWORD(pbColorsCurr, ((DWORD)iRep));
  4012.  
  4013.         // indexedColor
  4014.         WRITE_FLOAT(pbColorsCurr, pShape->m_aVertexColors[pShape->m_aReps[iRep].m_iFirst].r);    // red
  4015.         WRITE_FLOAT(pbColorsCurr, pShape->m_aVertexColors[pShape->m_aReps[iRep].m_iFirst].g);    // green
  4016.         WRITE_FLOAT(pbColorsCurr, pShape->m_aVertexColors[pShape->m_aReps[iRep].m_iFirst].b);    // blue
  4017.         WRITE_FLOAT(pbColorsCurr, pShape->m_aVertexColors[pShape->m_aReps[iRep].m_iFirst].a);    // alpha
  4018.     }
  4019.  
  4020.  
  4021.     hr = pxofSave->CreateDataObject(TID_D3DRMMeshVertexColors, NULL, NULL, cbColorsSize, pbColorsData, &pColorsDataObject);
  4022.     if (FAILED(hr))
  4023.     {
  4024.         cout << "AddVertexColors(): Could not create pColorsDataObject." << endl;
  4025.         goto e_Exit;
  4026.     }
  4027.  
  4028.  
  4029.     hr = pShapeDataObject->AddDataObject(pColorsDataObject);
  4030.     if (FAILED(hr))
  4031.     {
  4032.         cout << "AddVertexColors(): Could not add pColorsDataObject to pShapeDataObject." << endl;
  4033.         goto e_Exit;
  4034.     }
  4035.  
  4036.  
  4037. e_Exit:
  4038.  
  4039.     delete[] pbColorsData;
  4040.  
  4041.     if (pColorsDataObject)
  4042.         pColorsDataObject->Release();
  4043.  
  4044.  
  4045.     return hr;
  4046. }
  4047.  
  4048.  
  4049.  
  4050.  
  4051.  
  4052.  
  4053.  
  4054.  
  4055.  
  4056.  
  4057.  
  4058. HRESULT    AddRepInfo
  4059.         (
  4060.             SMesh*                    pShape, 
  4061.             LPDIRECTXFILEDATA        pShapeDataObject, 
  4062.             LPDIRECTXFILESAVEOBJECT    pxofSave
  4063.         ) 
  4064. {
  4065.     HRESULT    hr = S_OK;
  4066.  
  4067.     LPDIRECTXFILEDATA pRepsDataObject = NULL;
  4068.     PBYTE pbRepsData= NULL;
  4069.     UINT iRep;
  4070.     UINT cbRepsSize = sizeof(DWORD)                        // nIndices
  4071.                     + sizeof(DWORD)                        // nOriginalVertices
  4072.                     + pShape->m_nReps * sizeof(DWORD);    // indices
  4073.  
  4074.     PBYTE pbRepsCurr = pbRepsData = new BYTE[cbRepsSize];
  4075.     if (NULL == pbRepsData)
  4076.     {
  4077.         hr = E_OUTOFMEMORY;
  4078.         cout << "AddRepInfo(): Could not allocate memory for pbRepsData." << endl;
  4079.         goto e_Exit;
  4080.     }
  4081.  
  4082.  
  4083.     // nIndices
  4084.     WRITE_DWORD(pbRepsCurr, ((DWORD)pShape->m_nReps));
  4085.  
  4086.     // nOriginalVertices
  4087.     WRITE_DWORD(pbRepsCurr, ((DWORD)pShape->m_nPoints));
  4088.  
  4089.     // indices
  4090.     for (iRep = 0; iRep < pShape->m_nReps; iRep++)
  4091.         WRITE_DWORD(pbRepsCurr, ((DWORD)pShape->m_aReps[iRep].m_iFirst));
  4092.  
  4093.  
  4094.     hr = pxofSave->CreateDataObject(DXFILEOBJ_VertexDuplicationIndices, NULL, NULL, cbRepsSize, pbRepsData, &pRepsDataObject);
  4095.     if (FAILED(hr))
  4096.     {
  4097.         cout << "AddRepInfo(): Could not create pRepsDataObject." << endl;
  4098.         goto e_Exit;
  4099.     }
  4100.  
  4101.     hr = pShapeDataObject->AddDataObject(pRepsDataObject);
  4102.     if (FAILED(hr))
  4103.     {
  4104.         cout << "AddRepInfo(): Could not add pRepsDataObject to pShapeDataObject." << endl;
  4105.         goto e_Exit;
  4106.     }
  4107.  
  4108.  
  4109. e_Exit:
  4110.  
  4111.     delete[] pbRepsData;
  4112.  
  4113.     if (pRepsDataObject)
  4114.         pRepsDataObject->Release();
  4115.  
  4116.  
  4117.     return hr;
  4118. }
  4119.  
  4120.  
  4121.  
  4122.  
  4123.  
  4124.  
  4125.  
  4126.  
  4127.  
  4128.  
  4129.  
  4130.  
  4131.  
  4132. HRESULT    AddPatchMesh
  4133.         (
  4134.             SMesh*                    pShape, 
  4135.             LPDIRECTXFILEDATA        pFrameDataObject, 
  4136.             LPDIRECTXFILESAVEOBJECT    pxofSave
  4137.         ) 
  4138. {
  4139.     HRESULT    hr = S_OK;
  4140.     LPDIRECTXFILEDATA pShapeDataObject = NULL;
  4141.     PBYTE pbShapeData = NULL;
  4142.     UINT iFace, iRep;    // counters
  4143.     UINT cbShapeSize = sizeof(DWORD)                                                    // nVertices
  4144.                         + pShape->m_nReps * (3 * sizeof(float))                            // vertices
  4145.                         + sizeof(DWORD)                                                    // nPatches
  4146.                         + (pShape->m_nFaces + pShape->m_nFaceIndices) * sizeof(DWORD);    // patches
  4147.  
  4148.     PBYTE pbShapeCurr = pbShapeData    = new BYTE[cbShapeSize];
  4149.     if (NULL == pbShapeData)
  4150.     {
  4151.         hr = E_OUTOFMEMORY;
  4152.         cout << "AddPatchMesh(): Could not allocate memory for pbpShapeData." << endl;
  4153.         goto e_Exit;
  4154.     }
  4155.     
  4156.  
  4157.     // nVertices
  4158.     WRITE_DWORD(pbShapeCurr, ((DWORD)pShape->m_nPoints));
  4159.  
  4160.     // vertices
  4161.     for (iRep = 0; iRep < pShape->m_nReps; iRep++) 
  4162.     {
  4163.         WRITE_FLOAT(pbShapeCurr, pShape->m_aPoints[pShape->m_aReps[iRep].m_iFirst].vec[0]);
  4164.         WRITE_FLOAT(pbShapeCurr, pShape->m_aPoints[pShape->m_aReps[iRep].m_iFirst].vec[1]);
  4165.         WRITE_FLOAT(pbShapeCurr, pShape->m_aPoints[pShape->m_aReps[iRep].m_iFirst].vec[2]);
  4166.     }
  4167.  
  4168.     // nPatches
  4169.     WRITE_DWORD(pbShapeCurr, ((DWORD)pShape->m_nFaces));
  4170.  
  4171.     // faces
  4172.     for (iFace = 0; iFace < pShape->m_nFaces; iFace++) 
  4173.     {
  4174.         WRITE_DWORD(pbShapeCurr, ((DWORD)16));
  4175.  
  4176.         for (UINT iIndex = 0; iIndex < 16; iIndex++)
  4177.             WRITE_DWORD(pbShapeCurr, pShape->m_aFaces[iFace].m_aIndices[iIndex]);
  4178.     }
  4179.  
  4180.  
  4181.     hr = pxofSave->CreateDataObject(DXFILEOBJ_PatchMesh, NULL, NULL, cbShapeSize, pbShapeData, &pShapeDataObject);
  4182.     if (FAILED(hr))
  4183.     {
  4184.         cout << "AddPatchMesh(): Could not create pShapeDataObject." << endl;
  4185.         goto e_Exit;
  4186.     }
  4187.  
  4188.  
  4189.     // MeshTextureCoords
  4190.     if (pShape->m_nUVs > 0) 
  4191.     {
  4192.         hr = AddTexCoords(pShape, pShapeDataObject, pxofSave);
  4193.         if (FAILED(hr))
  4194.         {
  4195.             cout << "AddPatchMesh(): Could not add texture coordinate info." << endl;
  4196.             goto e_Exit;
  4197.         }
  4198.     }
  4199.  
  4200.     // MeshVertexColors
  4201. //    hr = AddVertexColors(pShape, pShapeDataObject, pxofSave),
  4202. //    if (FAILED(hr))
  4203. //    {
  4204. //        cout << "AddPatchMesh(): Could not add vertex color info." << endl;
  4205. //        goto e_Exit;
  4206. //    }
  4207.     
  4208.     // MeshMaterialList
  4209.     hr = AddMaterialList(pShape, pShapeDataObject, pxofSave);
  4210.     if (FAILED(hr))
  4211.     {
  4212.         cout << "AddPatchMesh(): Could not add materials info." << endl;
  4213.         goto e_Exit;
  4214.     }
  4215.  
  4216.     // VertexDuplicationIndices
  4217.     hr = AddRepInfo(pShape, pShapeDataObject, pxofSave);
  4218.     if (FAILED(hr))
  4219.     {
  4220.         cout << "AddPatchMesh(): Could not add rep info." << endl;
  4221.         goto e_Exit;
  4222.     }
  4223.  
  4224.     // XSkinMeshHeader
  4225.     if (pShape->m_nBones > 0) 
  4226.     {
  4227.         hr = AddSkin(pShape, pShapeDataObject, pxofSave);
  4228.         if (FAILED(hr))
  4229.         {
  4230.             cout << "AddPatchMesh(): Could not add skin info." << endl;
  4231.             goto e_Exit;
  4232.         }
  4233.     }
  4234.  
  4235.  
  4236.  
  4237.     hr = pFrameDataObject->AddDataObject(pShapeDataObject);
  4238.     if (FAILED(hr))
  4239.     {
  4240.         cout << "AddPatchMesh(): Could not add pShapeDataObject to pFrameDataObject." << endl;
  4241.         goto e_Exit;
  4242.     }
  4243.  
  4244.  
  4245. e_Exit:
  4246.  
  4247.     delete[] pbShapeData;
  4248.  
  4249.     if (pShapeDataObject)
  4250.         pShapeDataObject->Release();
  4251.  
  4252.  
  4253.     return hr;
  4254. }
  4255.  
  4256.  
  4257.  
  4258.  
  4259.  
  4260.  
  4261.  
  4262.  
  4263.  
  4264.  
  4265.  
  4266.  
  4267.  
  4268.  
  4269.  
  4270.  
  4271. HRESULT    AddPolyMesh
  4272.         (
  4273.             SMesh*                    pShape, 
  4274.             LPDIRECTXFILEDATA        pFrameDataObject, 
  4275.             LPDIRECTXFILESAVEOBJECT    pxofSave
  4276.         ) 
  4277. {
  4278.  
  4279.     HRESULT    hr = S_OK;
  4280.     LPDIRECTXFILEDATA pShapeDataObject = NULL;
  4281.     PBYTE pbMeshData = NULL;
  4282.     UINT iFace, iRep;    // counters
  4283.     UINT cbMeshSize = sizeof(DWORD)                                                    // nVertices
  4284.                     + pShape->m_nReps * (3 * sizeof(float))                            // vertices
  4285.                     + sizeof(DWORD)                                                    // nFaces
  4286.                     + (pShape->m_nFaces + pShape->m_nFaceIndices) * sizeof(DWORD);    // faces
  4287.  
  4288.     PBYTE pbMeshCurr = pbMeshData = new BYTE[cbMeshSize];
  4289.     if (NULL == pbMeshData)
  4290.     {
  4291.         hr = E_OUTOFMEMORY;
  4292.         cout << "AddPolyMesh(): Could not allocate memory for pbMeshData." << endl;
  4293.         goto e_Exit;
  4294.     }
  4295.     
  4296.  
  4297.     // nVertices
  4298.     WRITE_DWORD(pbMeshCurr, ((DWORD)pShape->m_nReps));
  4299.  
  4300.     // vertices
  4301.     for (iRep = 0; iRep < pShape->m_nReps; iRep++) 
  4302.     {
  4303.         WRITE_FLOAT(pbMeshCurr, pShape->m_aPoints[pShape->m_aReps[iRep].m_iFirst].vec[0]);
  4304.         WRITE_FLOAT(pbMeshCurr, pShape->m_aPoints[pShape->m_aReps[iRep].m_iFirst].vec[1]);
  4305.         WRITE_FLOAT(pbMeshCurr, pShape->m_aPoints[pShape->m_aReps[iRep].m_iFirst].vec[2]);
  4306.     }
  4307.  
  4308.     // nFaces
  4309.     WRITE_DWORD(pbMeshCurr, ((DWORD)pShape->m_nFaces));
  4310.  
  4311.     // faces
  4312.     for (iFace = 0; iFace < pShape->m_nFaces; iFace++) 
  4313.     {
  4314.         WRITE_DWORD(pbMeshCurr, ((DWORD)pShape->m_aFaces[iFace].m_nIndices));
  4315.  
  4316.         for (UINT iIndex = 0; iIndex < pShape->m_aFaces[iFace].m_nIndices; iIndex++)
  4317.             WRITE_DWORD(pbMeshCurr, ((DWORD)pShape->m_aFaces[iFace].m_aIndices[iIndex]));
  4318.     }
  4319.  
  4320.  
  4321.     hr = pxofSave->CreateDataObject(TID_D3DRMMesh, NULL, NULL, cbMeshSize, pbMeshData, &pShapeDataObject);
  4322.     if (FAILED(hr))
  4323.     {
  4324.         cout << "AddPolyMesh(): Could not create pShapeDataObject." << endl;
  4325.         goto e_Exit;
  4326.     }
  4327.  
  4328.  
  4329.     // MeshNormals
  4330.     if (pShape->m_nNormals > 0) 
  4331.     {
  4332.         hr = AddNormals(pShape, pShapeDataObject, pxofSave);
  4333.         if (FAILED(hr))
  4334.         {
  4335.             cout << "AddPolyMesh(): Could not add normal info." << endl;
  4336.             goto e_Exit;
  4337.         }
  4338.     }
  4339.  
  4340.  
  4341.     // MeshTextureCoords
  4342.     if (pShape->m_nUVs > 0) 
  4343.     {
  4344.         hr = AddTexCoords(pShape, pShapeDataObject, pxofSave);
  4345.         if (FAILED(hr))
  4346.         {
  4347.             cout << "AddPolyMesh(): Could not add texture coordinate info." << endl;
  4348.             goto e_Exit;
  4349.         }
  4350.     }
  4351.  
  4352.     // MeshVertexColors
  4353. //    hr = AddVertexColors(pShape, pShapeDataObject, pxofSave);
  4354. //    if (FAILED(hr))
  4355. //    {
  4356. //        cout << "AddPolyMesh(): Could not add vertex color info." << endl;
  4357. //        goto e_Exit;
  4358. //    }
  4359.  
  4360.     
  4361.     // MeshMaterialList
  4362.     hr = AddMaterialList(pShape, pShapeDataObject, pxofSave);
  4363.     if (FAILED(hr))
  4364.     {
  4365.         cout << "AddPolyMesh(): Could not add materials info." << endl;
  4366.         goto e_Exit;
  4367.     }
  4368.  
  4369.  
  4370.     // VertexDuplicationIndices
  4371.     hr = AddRepInfo(pShape, pShapeDataObject, pxofSave);
  4372.     if (FAILED(hr))
  4373.     {
  4374.         cout << "AddPolyMesh(): Could not add rep info." << endl;
  4375.         goto e_Exit;
  4376.     }
  4377.  
  4378.  
  4379.     // XSkinMeshHeader
  4380.     if (pShape->m_nBones > 0) 
  4381.     {
  4382.         hr = AddSkin(pShape, pShapeDataObject, pxofSave);
  4383.         if (FAILED(hr))
  4384.         {
  4385.             cout << "AddPolyMesh(): Could not add skin info." << endl;
  4386.             goto e_Exit;
  4387.         }
  4388.     }
  4389.  
  4390.  
  4391.     hr = pFrameDataObject->AddDataObject(pShapeDataObject);
  4392.     if (FAILED(hr))
  4393.     {
  4394.         cout << "AddPolyMesh(): Could not add pShapeDataObject to pFrameDataObject." << endl;
  4395.         goto e_Exit;
  4396.     }
  4397.  
  4398.  
  4399.  
  4400. e_Exit:
  4401.  
  4402.     delete[] pbMeshData;
  4403.  
  4404.     if (pShapeDataObject)
  4405.         pShapeDataObject->Release();
  4406.  
  4407.     return hr;
  4408. }
  4409.  
  4410.  
  4411.  
  4412.  
  4413.  
  4414.  
  4415.  
  4416.  
  4417.  
  4418. HRESULT    AddShape
  4419.         (
  4420.             MDagPath&                mdpTransform,
  4421.             bool                    bParentVisibility,
  4422.             LPDIRECTXFILEDATA        pParentFrameDataObject, 
  4423.             LPDIRECTXFILESAVEOBJECT    pxofSave
  4424.         ) 
  4425. {
  4426.     MStatus    stat;
  4427.     UINT i, j;
  4428.     HRESULT    hr = S_OK;
  4429.     MItDag itDag;
  4430.     MFnTransform fnTransform;
  4431.     char* szName;
  4432.     float* afLocalTransform;
  4433.     bool bVisibility, bLodVisibility, bOverrideEnabled, bOverrideVisibility;
  4434.     bool bIsVisible;
  4435.  
  4436.     LPDIRECTXFILEDATA    pFrameDataObject    = NULL;
  4437.     LPDIRECTXFILEDATA    pMatrixDataObject    = NULL;
  4438.  
  4439.     if (!mdpTransform.hasFn(MFn::kTransform))
  4440.     {
  4441.         cout << "AddShape(): Object at DAG path was not a transform." << endl;
  4442.         goto e_Exit;
  4443.  
  4444.     }
  4445.  
  4446.     stat = fnTransform.setObject(mdpTransform.node());
  4447.     if (!stat)
  4448.     {
  4449.         cout << "AddShape(): Could not read transform object." << endl;
  4450.         goto e_Exit;
  4451.     }
  4452.  
  4453.     // check if mesh is visible
  4454.     bVisibility = true;
  4455.     bLodVisibility = true;
  4456.     bOverrideEnabled = false;
  4457.     bOverrideVisibility = true;
  4458.  
  4459.     do    // ONCE
  4460.     {
  4461.         MPlug mpVisibility, mpLodVisibility, mpOverrideEnabled, mpOverrideVisibility;
  4462.  
  4463.         mpVisibility = fnTransform.findPlug("visibility", &stat);
  4464.         if (!stat)
  4465.             break;
  4466.  
  4467.         stat = mpVisibility.getValue(bVisibility);
  4468.         if (!stat)
  4469.             break;
  4470.  
  4471.         mpLodVisibility = fnTransform.findPlug("lodVisibility", &stat);
  4472.         if (!stat)
  4473.             break;
  4474.  
  4475.         stat = mpLodVisibility.getValue(bLodVisibility);
  4476.         if (!stat)
  4477.             break;
  4478.  
  4479.         mpOverrideEnabled = fnTransform.findPlug("overrideEnabled", &stat);
  4480.         if (!stat)
  4481.             break;
  4482.  
  4483.         stat = mpOverrideEnabled.getValue(bOverrideEnabled);
  4484.         if (!stat)
  4485.             break;
  4486.  
  4487.         mpOverrideVisibility = fnTransform.findPlug("overrideVisibility", &stat);
  4488.         if (!stat)
  4489.             break;
  4490.  
  4491.         stat = mpOverrideVisibility.getValue(bOverrideVisibility);
  4492.         if (!stat)
  4493.             break;
  4494.     }
  4495.     while (false);
  4496.  
  4497.     bIsVisible = bParentVisibility && bLodVisibility && (!bOverrideEnabled || bOverrideVisibility);
  4498.  
  4499.     
  4500.     // shape name
  4501.     szName = NULL;
  4502.     szName = new char[1 + mdpTransform.partialPathName().length()];
  4503.     if (szName == NULL) 
  4504.     {
  4505.         hr = E_OUTOFMEMORY;
  4506.         cout << "AddShape():  Could not allocate memory for szName." << endl;
  4507.         goto e_Exit;
  4508.     }
  4509.  
  4510.     strcpy(szName, mdpTransform.partialPathName().asChar());
  4511.     for (i = 0; szName[i] != '\0'; i++)        // maya names may contain '|' or perhaps even ' '
  4512.     {
  4513.         if (szName[i] == ' ' || szName[i] == '|')
  4514.             szName[i] = '_';
  4515.     }
  4516.  
  4517.     hr = g_Arrays.Add(STRING, szName);
  4518.     if (FAILED(hr))
  4519.         goto e_Exit;
  4520.  
  4521.     cout << "\tReading \"" << mdpTransform.fullPathName().asChar() << "\"...";
  4522.     
  4523.     // local transform
  4524.     afLocalTransform = NULL;
  4525.     afLocalTransform = new float[16];
  4526.     if (afLocalTransform == NULL)
  4527.     {
  4528.         hr = E_OUTOFMEMORY;
  4529.         cout << "AddShape():  Could not allocate memory for afLocalTransform." << endl;
  4530.         goto e_Exit;
  4531.     }
  4532.  
  4533.     for (i = 0; i < 4; i++)
  4534.     {
  4535.         for (j = 0; j < 4; j++)
  4536.         {
  4537.             afLocalTransform[i * 4 + j] = (float)fnTransform.transformation().asMatrix()[i][j];
  4538.         }
  4539.     }
  4540.  
  4541.     hr = g_Arrays.Add(FLOAT_ARRAY, afLocalTransform);
  4542.     if (FAILED(hr))
  4543.         goto e_Exit;
  4544.  
  4545.     cout << "TRANSFORM";
  4546.  
  4547.     // Frame
  4548.     hr = pxofSave->CreateDataObject(TID_D3DRMFrame, szName, NULL, 0, NULL, &pFrameDataObject);
  4549.     if (FAILED(hr))
  4550.     {
  4551.         cout << "AddShape(): Could not create pFrameDataObject." << endl;
  4552.         goto e_Exit;
  4553.     }
  4554.  
  4555.     // FrameTransformMatrix
  4556.     hr = pxofSave->CreateDataObject(TID_D3DRMFrameTransformMatrix, NULL, NULL, 16 * sizeof(float), afLocalTransform, &pMatrixDataObject);
  4557.     if (FAILED(hr))
  4558.     {
  4559.         cout << "AddShape(): Could not create pMatrixDataObject." << endl;
  4560.         goto e_Exit;
  4561.     }
  4562.  
  4563.     hr = pFrameDataObject->AddDataObject(pMatrixDataObject);
  4564.     if (FAILED(hr))
  4565.     {
  4566.         cout << "AddShape(): Could not add pMatrixDataObject to pFrameDataObject." << endl;
  4567.         goto e_Exit;
  4568.     }
  4569.  
  4570.  
  4571.     // the reason for the braces here is to place Mesh in a local scope so that will be deleted quickly 
  4572.     if (mdpTransform.hasFn(MFn::kJoint))
  4573.     {    // bone
  4574.         cout << "/BONE" << endl;
  4575.     }
  4576.     else if (bIsVisible && mdpTransform.hasFn(MFn::kMesh))
  4577.     {    // poly mesh
  4578.         SMesh Mesh;
  4579.         MDagPath mdpMesh = mdpTransform;
  4580.  
  4581.         cout << "(MESH)" << endl;
  4582.  
  4583.         stat = mdpMesh.extendToShape();
  4584.         if (!stat)
  4585.         {
  4586.             hr = E_FAIL;
  4587.             cout << "AddShape(): Could not extend to shape node." << endl;
  4588.             goto e_Exit;
  4589.         }
  4590.         
  4591.         hr = LoadPolyMesh(mdpTransform, mdpMesh, &Mesh);
  4592.         if (FAILED(hr))
  4593.         {
  4594.             cout << "AddShape(): Could not load poly-mesh." << endl;
  4595.             goto e_Exit;
  4596.         }
  4597.  
  4598.         if (Mesh.m_kType == SMesh::POLY_MESH)
  4599.         {
  4600.             hr = AddPolyMesh(&Mesh, pFrameDataObject, pxofSave);
  4601.             if (FAILED(hr))
  4602.             {
  4603.                 cout << "AddShape(): Could not add mesh" << endl;
  4604.                 goto e_Exit;
  4605.             }
  4606.         }
  4607.     }
  4608.     else if (bIsVisible && mdpTransform.hasFn(MFn::kNurbsSurface))
  4609.     {
  4610.         SMesh Mesh;
  4611.         MDagPath mdpNurbs = mdpTransform;
  4612.  
  4613.         cout << "(NURBS) (ignored)" << endl;
  4614.  
  4615.         stat = mdpNurbs.extendToShape();
  4616.         if (!stat)
  4617.         {
  4618.             hr = E_FAIL;
  4619.             cout << "AddShape(): Could not extend to shape node." << endl;
  4620.             goto e_Exit;
  4621.         }
  4622.         
  4623. //        hr = LoadPatchMesh(mdpTransform, mdpNurbs, &Mesh);
  4624.         if (FAILED(hr))
  4625.         {
  4626.             cout << "AddShape(): Could not load patch-mesh." << endl;
  4627.             goto e_Exit;
  4628.         }
  4629.  
  4630.         if (Mesh.m_kType == SMesh::POLY_MESH)
  4631.         {
  4632.             hr = AddPolyMesh(&Mesh, pFrameDataObject, pxofSave);
  4633.             if (FAILED(hr))
  4634.             {
  4635.                 cout << "AddShape(): Could not add tesselated patch-mesh" << endl;
  4636.                 goto e_Exit;
  4637.             }
  4638.         }
  4639.         else if (Mesh.m_kType == SMesh::PATCH_MESH)
  4640.         {
  4641.             hr = AddPatchMesh(&Mesh, pFrameDataObject, pxofSave);
  4642.             if (FAILED(hr))
  4643.             {
  4644.                 cout << "AddShape(): Could not add patch-mesh" << endl;
  4645.                 goto e_Exit;
  4646.             }
  4647.         }
  4648.     }
  4649.     else
  4650.     {
  4651.         cout << endl;
  4652.     }
  4653.  
  4654.  
  4655.     // add children
  4656.     itDag.reset(mdpTransform.node(), MItDag::kBreadthFirst, MFn::kTransform);
  4657.  
  4658.     itDag.next();
  4659.  
  4660.     for (; !itDag.isDone() && itDag.depth() == 1; itDag.next())
  4661.     {
  4662.         MDagPath mdpChild;
  4663.  
  4664.         itDag.getPath(mdpChild);
  4665.  
  4666. #ifdef NO_INTERMEDIATE_OBJECTS
  4667.         if (MFnDagNode(mdpChild).isIntermediateObject()) 
  4668.             continue;
  4669. #endif
  4670.  
  4671.         hr = AddShape(mdpChild, bIsVisible, pFrameDataObject, pxofSave);
  4672.         if (FAILED(hr))
  4673.             cout << "AddShape(): Could not add child shape.  Ignoring..." << endl;
  4674.     }
  4675.         
  4676.     
  4677.  
  4678.     hr = pParentFrameDataObject->AddDataObject(pFrameDataObject);
  4679.     if (FAILED(hr))
  4680.     {
  4681.         cout << "AddShape(): Could not add pFrameDataObject to pParentFrameDataObject." << endl;
  4682.         goto e_Exit;
  4683.     }
  4684.  
  4685.     g_AddedPaths.append(mdpTransform);
  4686.  
  4687. e_Exit:
  4688.     if (pMatrixDataObject)
  4689.         pMatrixDataObject->Release();
  4690.  
  4691.     if (pFrameDataObject)
  4692.         pFrameDataObject->Release();
  4693.  
  4694.     return hr;
  4695. }
  4696.  
  4697. #define SWAP(array, i1, i2)        {    UINT temp = (array)[(i1)]; (array)[(i1)] = (array)[(i2)]; (array)[(i2)] = temp;    }
  4698.  
  4699. HRESULT LoadKeyframedAnims
  4700.         (
  4701.             UINT* pnAnims, 
  4702.             SAnim** paAnims
  4703.         )
  4704. {
  4705.     HRESULT    hr = S_OK;
  4706.     MStatus stat = MS::kSuccess;
  4707.  
  4708.     MAnimControl mAnimCtrl;
  4709.     MFnTransform fnTransform;
  4710.     SAnim* aAnims = NULL;
  4711.     UINT nFPS;    // num frames per second
  4712.     float fTimeFactor;
  4713.     UINT nAnims = 0, nPending, nActive;
  4714.     UINT iAnim, iPath, iPlug, iCurve, iKey, iPending, iRow, iCol;    // counters
  4715.     UINT* aiCurKey = NULL;
  4716.     UINT* aiIndices = NULL;
  4717.     MIntArray AnimPaths;
  4718.     float afMatrix[16];
  4719.     char* pcAnim;
  4720.     char* szAnim = NULL;
  4721.     MTime mtMinTime, mtOriginalTime;
  4722.     MTimeArray* amatTimes = NULL;
  4723.  
  4724.     mtOriginalTime = mAnimCtrl.currentTime();
  4725.  
  4726.     // calculate the frames per second
  4727.     switch(MTime::uiUnit()) 
  4728.     {
  4729.         case MTime::kSeconds:        // 1 fps
  4730.             nFPS = 1;
  4731.             break;
  4732.         case MTime::kMilliseconds:    // 1000 fps
  4733.             nFPS = 1000;
  4734.             break;
  4735.         case MTime::kGames:            // 15 fps
  4736.             nFPS = 15;
  4737.             break;
  4738.         case MTime::kFilm:            // 24 fps
  4739.             nFPS = 24;
  4740.             break;
  4741.         case MTime::kPALFrame:        // 25 fps
  4742.             nFPS = 25;
  4743.             break;
  4744.         case MTime::kNTSCFrame:        // 30 fps
  4745.             nFPS = 30;
  4746.             break;
  4747.         case MTime::kShowScan:        // 48 fps
  4748.             nFPS = 48;
  4749.             break;
  4750.         case MTime::kPALField:        // 50 fps
  4751.             nFPS = 50;
  4752.             break;
  4753.         case MTime::kNTSCField:        // 60 fps
  4754.             nFPS = 60;
  4755.             break;
  4756.         default:
  4757.             nFPS = 1;
  4758.             break;
  4759.     };
  4760.  
  4761.     fTimeFactor = 3600.0f / (float)nFPS;
  4762.  
  4763.  
  4764.  
  4765.     // find animated objects
  4766.     for (iPath = 0; iPath < g_AddedPaths.length(); iPath++)
  4767.     {
  4768.         MFnTransform fnTransform;
  4769.  
  4770.         stat = fnTransform.setObject(g_AddedPaths[iPath]);
  4771.         if (!stat)
  4772.             continue;
  4773.  
  4774.         if (!MAnimUtil::isAnimated(g_AddedPaths[iPath], false))
  4775.             continue;
  4776.  
  4777.         AnimPaths.append(iPath);
  4778.     }
  4779.  
  4780.     nAnims = AnimPaths.length();
  4781.  
  4782.     if (0 == nAnims)
  4783.         goto e_Exit;
  4784.  
  4785.     amatTimes = new MTimeArray[nAnims];
  4786.     if (NULL == amatTimes)
  4787.     {
  4788.         hr = E_OUTOFMEMORY;
  4789.         cout << "LoadKeyframedAnims(): Could not allocate times array." << endl;
  4790.         goto e_Exit;
  4791.     }
  4792.  
  4793.     aAnims = new SAnim[nAnims];
  4794.     if (NULL == aAnims)
  4795.     {
  4796.         hr = E_OUTOFMEMORY;
  4797.         cout << "LoadKeyframedAnims(): Could not allocate anim array." << endl;
  4798.         goto e_Exit;
  4799.     }
  4800.  
  4801.     aiCurKey = new UINT[nAnims];
  4802.     if (NULL == aiCurKey)
  4803.     {
  4804.         hr = E_OUTOFMEMORY;
  4805.         cout << "LoadKeyframedAnims(): Could not allocate current-key array." << endl;
  4806.         goto e_Exit;
  4807.     }
  4808.  
  4809.     aiIndices = new UINT[nAnims];
  4810.     if (NULL == aiIndices)
  4811.     {
  4812.         hr = E_OUTOFMEMORY;
  4813.         cout << "LoadKeyframedAnims(): Could not allocate indirection array." << endl;
  4814.         goto e_Exit;
  4815.     }
  4816.  
  4817.     // consolidate individual anim curves for each animated path
  4818.     for (nActive = 0, nPending = 0, iAnim = 0; iAnim < nAnims; iAnim++)
  4819.     {
  4820.         MPlugArray AnimPlugs;
  4821.  
  4822.         aiCurKey[iAnim] = 0;
  4823.         aiIndices[iAnim] = iAnim;
  4824.  
  4825.         MAnimUtil::findAnimatedPlugs(g_AddedPaths[AnimPaths[iAnim]], AnimPlugs, false, &stat);
  4826.         if (!stat)
  4827.         {
  4828.             cout << "LoadKeyframedAnims(): Ignoring animation because could not find animated plugs." << endl;
  4829.             continue;
  4830.         }
  4831.  
  4832.         for (iPlug = 0; iPlug < AnimPlugs.length(); iPlug++)
  4833.         {
  4834.             MObjectArray Curves;
  4835.  
  4836.             MAnimUtil::findAnimation(AnimPlugs[iPlug], Curves, &stat);
  4837.             if (!stat)
  4838.             {
  4839.                 cout << "LoadKeyframedAnims(): Ignoring anim-plug because could not find animation." << endl;
  4840.                 continue;
  4841.             }
  4842.  
  4843.             for (iCurve = 0; iCurve < Curves.length(); iCurve++)
  4844.             {
  4845.                 UINT iTime;
  4846.                 MFnAnimCurve fnCurve(Curves[iCurve], &stat);
  4847.                 if (!stat)
  4848.                 {
  4849.                     cout << "LoadKeyframedAnims(): Ignoring anim-curve because it could not be read with anim-curve function set." << endl;
  4850.                     continue;
  4851.                 }
  4852.  
  4853.                 for (iTime = 0, iKey = 0; iKey < fnCurve.numKeys(); iKey++)
  4854.                 {
  4855.                     MTime mtTime = fnCurve.time(iKey, &stat);
  4856.                     if (!stat)
  4857.                     {
  4858.                         cout << "LoadKeyframedAnims(): Ignoring anim-curve-key because it could not be read." << endl;
  4859.                         continue;
  4860.                     }
  4861.  
  4862.                     for (; iTime < amatTimes[iAnim].length() && mtTime > amatTimes[iAnim][iTime]; iTime++);
  4863.  
  4864.                     if (iTime < amatTimes[iAnim].length() && mtTime < amatTimes[iAnim][iTime])
  4865.                     {
  4866.                         amatTimes[iAnim].insert(mtTime, iTime);
  4867.                     }
  4868.                     else if (iTime == amatTimes[iAnim].length())
  4869.                     {
  4870.                         amatTimes[iAnim].append(mtTime);
  4871.                     }
  4872.                 }    // loop through keys
  4873.             }    // loop through curves
  4874.         }    // loop through plugs
  4875.  
  4876.  
  4877.         // get name
  4878.         delete[] szAnim;
  4879.         szAnim = NULL;
  4880.         szAnim = new char[g_AddedPaths[AnimPaths[iAnim]].partialPathName().length() + 1];
  4881.         if (NULL == szAnim)
  4882.         {
  4883.             hr = E_OUTOFMEMORY;
  4884.             cout << "AddAnimation(): Could not allocate string for anim name." << endl;
  4885.             goto e_Exit;
  4886.         }
  4887.  
  4888.         strcpy(szAnim, g_AddedPaths[AnimPaths[iAnim]].partialPathName().asChar());
  4889.         for (pcAnim = szAnim; *pcAnim != '\0'; pcAnim++)
  4890.         {
  4891.             if (*pcAnim == ' ' || *pcAnim == '|')
  4892.                 *pcAnim = '_';
  4893.         }
  4894.  
  4895.         aAnims[iAnim].m_szName = szAnim;
  4896.         g_Arrays.Add(STRING, aAnims[iAnim].m_szName);
  4897.         szAnim = NULL;
  4898.         
  4899.         
  4900.         
  4901.         aAnims[iAnim].m_nKeys = amatTimes[iAnim].length();
  4902.  
  4903.         if (0 == aAnims[iAnim].m_nKeys)
  4904.             continue;
  4905.  
  4906.         aAnims[iAnim].m_aKeys = new SKey[aAnims[iAnim].m_nKeys];
  4907.         if (NULL == aAnims[iAnim].m_aKeys)
  4908.         {
  4909.             hr = E_OUTOFMEMORY;
  4910.             cout << "LoadKeyframedAnims(): Could not allocate anim-keys." << endl;
  4911.             goto e_Exit;
  4912.         }
  4913.  
  4914.         SWAP(aiIndices, iAnim, nPending);
  4915.         nPending++;
  4916.     }    // loop through animated paths
  4917.  
  4918.  
  4919.  
  4920.     while (nPending + nActive > 0)
  4921.     {
  4922.         iPending = 0;
  4923.  
  4924.         while (iPending < nPending)
  4925.         {
  4926.             iAnim = aiIndices[iPending];
  4927.  
  4928.             if (0 == nActive || amatTimes[iAnim][aiCurKey[iAnim]] <= mtMinTime)
  4929.             {
  4930.                 mtMinTime = amatTimes[iAnim][aiCurKey[iAnim]];
  4931.                 nPending--;
  4932.                 nActive++;
  4933.                 SWAP(aiIndices, iPending, nPending);
  4934.                 SWAP(aiIndices, nPending, nAnims - nActive);
  4935.                 continue;
  4936.             }
  4937.  
  4938.             iPending++;
  4939.         }
  4940.  
  4941.         mAnimCtrl.setCurrentTime(mtMinTime);    // set time to mtMinTime
  4942.  
  4943.         while (nActive > 0)
  4944.         {
  4945.             iAnim = aiIndices[nAnims - nActive];
  4946.             
  4947.             if (mtMinTime < amatTimes[iAnim][aiCurKey[iAnim]])
  4948.             {
  4949.                 mtMinTime = amatTimes[iAnim][aiCurKey[iAnim]];
  4950.                 break;
  4951.             }
  4952.  
  4953.             // read matrix
  4954.             stat = fnTransform.setObject(g_AddedPaths[AnimPaths[iAnim]]);
  4955.             if (!stat)
  4956.             {
  4957.                 hr = E_FAIL;
  4958.                 cout << "LoadKeyframedAnims(): Could not read transform object using function set.  Aborting..." << endl;
  4959.                 goto e_Exit;
  4960.             }
  4961.  
  4962.             for (iRow = 0; iRow < 4; iRow++)
  4963.                 for (iCol = 0; iCol < 4; iCol++)
  4964.                     afMatrix[iRow * 4 + iCol] = (float)fnTransform.transformation().asMatrix()[iRow][iCol];
  4965.  
  4966.             aAnims[iAnim].m_aKeys[aiCurKey[iAnim]].m_iFrame = (UINT)((float)mtMinTime.value() * fTimeFactor);
  4967.  
  4968.             if (!DtMatrixGetTransforms(afMatrix, 
  4969.                                         aAnims[iAnim].m_aKeys[aiCurKey[iAnim]].m_afPosition, 
  4970.                                         aAnims[iAnim].m_aKeys[aiCurKey[iAnim]].m_afScale,                
  4971.                                         aAnims[iAnim].m_aKeys[aiCurKey[iAnim]].m_afQuaternion,                
  4972.                                         aAnims[iAnim].m_aKeys[aiCurKey[iAnim]].m_afRotation))
  4973.             {
  4974.                 cout << "LoadKeyframedAnims(): Error in getting TRS components." << endl;
  4975.                 goto e_Exit;
  4976.             }
  4977.  
  4978.             aAnims[iAnim].m_aKeys[aiCurKey[iAnim]].m_afQuaternion[0] = -aAnims[iAnim].m_aKeys[aiCurKey[iAnim]].m_afQuaternion[0];
  4979.  
  4980.             aiCurKey[iAnim]++;
  4981.  
  4982.             if (aiCurKey[iAnim] < aAnims[iAnim].m_nKeys)
  4983.             {
  4984.                 SWAP(aiIndices, nAnims - nActive, nPending);
  4985.                 nPending++;
  4986.             }
  4987.  
  4988.             nActive--;
  4989.         } 
  4990.     }
  4991.  
  4992.  
  4993.  
  4994.  
  4995. e_Exit:
  4996.         
  4997.  
  4998.     mAnimCtrl.setCurrentTime(mtOriginalTime);
  4999.  
  5000.     if (FAILED(hr))
  5001.     {
  5002.         delete[] aAnims;
  5003.         nAnims = 0;
  5004.         aAnims = NULL;
  5005.     }
  5006.  
  5007.     delete[] amatTimes;
  5008.     delete[] aiCurKey;
  5009.     delete[] aiIndices;
  5010.     delete[] szAnim;
  5011.  
  5012.     *pnAnims = nAnims;
  5013.     *paAnims = aAnims;
  5014.  
  5015.     return hr;
  5016. }
  5017.  
  5018.  
  5019.  
  5020.  
  5021.  
  5022.  
  5023. HRESULT LoadFixedStepAnims
  5024.         (
  5025.             UINT* pnAnims, 
  5026.             SAnim** paAnims
  5027.         )
  5028. {
  5029.     HRESULT    hr = S_OK;
  5030.     MStatus stat = MS::kSuccess;
  5031.  
  5032.     MAnimControl mAnimCtrl;
  5033.     MFnTransform fnTransform;
  5034.     SAnim* aAnims = NULL;
  5035.     UINT nFPS;    // num frames per second
  5036.     float fTimeFactor;
  5037.     UINT nAnims = 0;
  5038.     UINT iAnim, iPath, iRow, iCol, iKey;    // counters
  5039.     MIntArray AnimPaths;
  5040.     float afMatrix[16];
  5041.     char* pcAnim;
  5042.     char* szAnim = NULL;
  5043.     MTimeArray matKeys;
  5044.     MTime mtKey, mtMinTime, mtOriginalTime;
  5045.  
  5046.     mtOriginalTime = mAnimCtrl.currentTime();
  5047.  
  5048.     // calculate the frames per second
  5049.     switch(MTime::uiUnit()) 
  5050.     {
  5051.         case MTime::kSeconds:        // 1 fps
  5052.             nFPS = 1;
  5053.             break;
  5054.         case MTime::kMilliseconds:    // 1000 fps
  5055.             nFPS = 1000;
  5056.             break;
  5057.         case MTime::kGames:            // 15 fps
  5058.             nFPS = 15;
  5059.             break;
  5060.         case MTime::kFilm:            // 24 fps
  5061.             nFPS = 24;
  5062.             break;
  5063.         case MTime::kPALFrame:        // 25 fps
  5064.             nFPS = 25;
  5065.             break;
  5066.         case MTime::kNTSCFrame:        // 30 fps
  5067.             nFPS = 30;
  5068.             break;
  5069.         case MTime::kShowScan:        // 48 fps
  5070.             nFPS = 48;
  5071.             break;
  5072.         case MTime::kPALField:        // 50 fps
  5073.             nFPS = 50;
  5074.             break;
  5075.         case MTime::kNTSCField:        // 60 fps
  5076.             nFPS = 60;
  5077.             break;
  5078.         default:
  5079.             nFPS = 1;
  5080.             break;
  5081.     };
  5082.  
  5083.     fTimeFactor = 3600.0f / (float)nFPS;
  5084.  
  5085.  
  5086.     for (mtKey = MAnimControl::minTime(); mtKey <= MAnimControl::maxTime(); mtKey += g_iFrameStep)
  5087.         matKeys.append(mtKey);
  5088.  
  5089.  
  5090.     // find animated objects
  5091.     for (iPath = 0; iPath < g_AddedPaths.length(); iPath++)
  5092.     {
  5093.         MFnTransform fnTransform;
  5094.  
  5095.         stat = fnTransform.setObject(g_AddedPaths[iPath]);
  5096.         if (!stat)
  5097.             continue;
  5098.  
  5099.         if (!g_bAnimateEverything && !MAnimUtil::isAnimated(g_AddedPaths[iPath], false))
  5100.             continue;
  5101.  
  5102.         AnimPaths.append(iPath);
  5103.     }
  5104.  
  5105.     nAnims = AnimPaths.length();
  5106.  
  5107.     if (0 == nAnims)
  5108.         goto e_Exit;
  5109.  
  5110.     aAnims = new SAnim[nAnims];
  5111.     if (NULL == aAnims)
  5112.     {
  5113.         hr = E_OUTOFMEMORY;
  5114.         cout << "LoadFixedStepAnims(): Could not allocate anim array." << endl;
  5115.         goto e_Exit;
  5116.     }
  5117.  
  5118.  
  5119.  
  5120.     // consolidate individual anim curves for each animated path
  5121.     for (iAnim = 0; iAnim < nAnims; iAnim++)
  5122.     {
  5123.         // get name
  5124.         delete[] szAnim;
  5125.         szAnim = NULL;
  5126.         szAnim = new char[g_AddedPaths[AnimPaths[iAnim]].partialPathName().length() + 1];
  5127.         if (NULL == szAnim)
  5128.         {
  5129.             hr = E_OUTOFMEMORY;
  5130.             cout << "AddAnimation(): Could not allocate string for anim name." << endl;
  5131.             goto e_Exit;
  5132.         }
  5133.  
  5134.         strcpy(szAnim, g_AddedPaths[AnimPaths[iAnim]].partialPathName().asChar());
  5135.         for (pcAnim = szAnim; *pcAnim != '\0'; pcAnim++)
  5136.         {
  5137.             if (*pcAnim == ' ' || *pcAnim == '|')
  5138.                 *pcAnim = '_';
  5139.         }
  5140.  
  5141.         aAnims[iAnim].m_szName = szAnim;
  5142.         g_Arrays.Add(STRING, aAnims[iAnim].m_szName);
  5143.         szAnim = NULL;
  5144.         
  5145.         
  5146.         
  5147.         aAnims[iAnim].m_nKeys = matKeys.length();
  5148.         if (0 == aAnims[iAnim].m_nKeys)
  5149.             continue;
  5150.  
  5151.         aAnims[iAnim].m_aKeys = new SKey[aAnims[iAnim].m_nKeys];
  5152.         if (NULL == aAnims[iAnim].m_aKeys)
  5153.         {
  5154.             hr = E_OUTOFMEMORY;
  5155.             cout << "LoadFixedStepAnims(): Could not allocate anim-keys." << endl;
  5156.             goto e_Exit;
  5157.         }
  5158.     }    // loop through animated paths
  5159.  
  5160.  
  5161.     for (iKey = 0; iKey < matKeys.length(); iKey++)
  5162.     {
  5163.         mAnimCtrl.setCurrentTime(matKeys[iKey]);    // update time
  5164.  
  5165.         for (iAnim = 0; iAnim < nAnims; iAnim++)
  5166.         {
  5167.             // read matrix
  5168.             stat = fnTransform.setObject(g_AddedPaths[AnimPaths[iAnim]]);
  5169.             if (!stat)
  5170.             {
  5171.                 hr = E_FAIL;
  5172.                 cout << "LoadFixedStepAnims(): Could not read transform object using function set.  Aborting..." << endl;
  5173.                 goto e_Exit;
  5174.             }
  5175.  
  5176.             for (iRow = 0; iRow < 4; iRow++)
  5177.                 for (iCol = 0; iCol < 4; iCol++)
  5178.                     afMatrix[iRow * 4 + iCol] = (float)fnTransform.transformation().asMatrix()[iRow][iCol];
  5179.  
  5180.             aAnims[iAnim].m_aKeys[iKey].m_iFrame = (UINT)((float)matKeys[iKey].value() * fTimeFactor);
  5181.  
  5182.             if (!DtMatrixGetTransforms(afMatrix, 
  5183.                                         aAnims[iAnim].m_aKeys[iKey].m_afPosition, 
  5184.                                         aAnims[iAnim].m_aKeys[iKey].m_afScale,                
  5185.                                         aAnims[iAnim].m_aKeys[iKey].m_afQuaternion,                
  5186.                                         aAnims[iAnim].m_aKeys[iKey].m_afRotation))
  5187.             {
  5188.                 cout << "LoadFixedStepAnims(): Error in getting TRS components." << endl;
  5189.                 goto e_Exit;
  5190.             }
  5191.  
  5192.             aAnims[iAnim].m_aKeys[iKey].m_afQuaternion[0] = -aAnims[iAnim].m_aKeys[iKey].m_afQuaternion[0];
  5193.  
  5194.         } // loop through animated objects
  5195.  
  5196.     } // loop through keys
  5197.  
  5198.  
  5199.  
  5200.  
  5201. e_Exit:
  5202.         
  5203.  
  5204.     mAnimCtrl.setCurrentTime(mtOriginalTime);
  5205.  
  5206.     if (FAILED(hr))
  5207.     {
  5208.         delete[] aAnims;
  5209.         nAnims = 0;
  5210.         aAnims = NULL;
  5211.     }
  5212.  
  5213.     delete[] szAnim;
  5214.  
  5215.     *pnAnims = nAnims;
  5216.     *paAnims = aAnims;
  5217.  
  5218.     return hr;
  5219. }
  5220.  
  5221.  
  5222.  
  5223.  
  5224.  
  5225.  
  5226.  
  5227. HRESULT    AddScene
  5228.         (
  5229.             const char*    szFile
  5230.         ) 
  5231. {
  5232.     HRESULT    hr    = S_OK;
  5233.     MStatus stat = MS::kSuccess;
  5234.  
  5235.     UINT iPath;
  5236.     MDagPathArray VisiblePaths;
  5237.  
  5238.     LPDIRECTXFILE pxofApi = NULL;
  5239.     LPDIRECTXFILESAVEOBJECT pxofSave = NULL; 
  5240.  
  5241.     LPDIRECTXFILEDATA pAnimSetObject       = NULL;
  5242.     LPDIRECTXFILEDATA pRootFrameObject     = NULL;
  5243.     LPDIRECTXFILEDATA pRootTransformObject = NULL;
  5244.  
  5245.     UINT nAnims, iAnim;
  5246.     SAnim* aAnims = NULL;
  5247.  
  5248.     float rgfIdentity[16] = {1.0f, 0.0f, 0.0f, 0.0f,
  5249.                              0.0f, 1.0f, 0.0f, 0.0f,
  5250.                              0.0f, 0.0f, 1.0f, 0.0f,
  5251.                              0.0f, 0.0f, 0.0f, 1.0f};
  5252.  
  5253.  
  5254.     MItDag itDag2(MItDag::kDepthFirst, MFn::kTransform);
  5255.     MItDag itIkEffectors(MItDag::kDepthFirst, MFn::kIkEffector);
  5256.  
  5257.     MItDag itDag(MItDag::kBreadthFirst, MFn::kTransform, &stat);
  5258.     if (!stat)
  5259.     {
  5260.         hr = E_FAIL;
  5261.         cout << "AddScene(): Could not traverse nodes." << endl;
  5262.         goto e_Exit;
  5263.     }
  5264.  
  5265. #ifdef ALWAYS_TESSELATE_NURBS
  5266.     g_bExportPatches = false;
  5267. #endif
  5268.  
  5269.  
  5270.     // turn off visible objects  (this is done to speed up the animation)
  5271.     for (itDag2.reset(); !itDag2.isDone(); itDag2.next())
  5272.     {
  5273.         MPlug Visibility;
  5274.         MDagPath dagPath;
  5275.         MFnDagNode fnDag;
  5276.         bool bIsVisible;
  5277.  
  5278.         stat = itDag2.getPath(dagPath);
  5279.         if (!stat)
  5280.             continue;
  5281.         
  5282.         stat = fnDag.setObject(dagPath);
  5283.         if (!stat)
  5284.             continue;
  5285.  
  5286.         Visibility = fnDag.findPlug("visibility", &stat);
  5287.         if (!stat)
  5288.             continue;
  5289.  
  5290.         stat = Visibility.getValue(bIsVisible);
  5291.         if (!stat || !bIsVisible)
  5292.             continue;
  5293.  
  5294.         stat = Visibility.setValue(false);
  5295.         if (!stat)
  5296.             continue;
  5297.  
  5298.         VisiblePaths.append(dagPath);
  5299.     }
  5300.  
  5301.  
  5302.     cout << "Exporting to " << szFile << " ..." << endl;
  5303.  
  5304.  
  5305.     // create xofapi object.
  5306.     hr = DirectXFileCreate(&pxofApi);
  5307.     if (FAILED(hr))
  5308.     {
  5309.         cout << "AddScene(): Could not create xofapi object." << endl;
  5310.         goto e_Exit;
  5311.     }
  5312.  
  5313.  
  5314.     // register templates for d3drm.
  5315.     hr = pxofApi->RegisterTemplates((LPVOID)D3DRM_XTEMPLATES, D3DRM_XTEMPLATE_BYTES);
  5316.     if (FAILED(hr))
  5317.     {
  5318.         cout << "AddScene(): Could not register D3D templates." << endl;
  5319.         goto e_Exit;
  5320.     }
  5321.  
  5322.  
  5323.     // register extra templates for skinning info and vertex duplication
  5324.     hr = pxofApi->RegisterTemplates((LPVOID)XSKINEXP_TEMPLATES, strlen(XSKINEXP_TEMPLATES));
  5325.     if (FAILED(hr))
  5326.     {
  5327.         cout << "AddScene(): Could not register Skinning and/or Vertex Duplication templates." << endl;
  5328.         goto e_Exit;
  5329.     }
  5330.  
  5331.  
  5332.     // create save object.
  5333.     hr = pxofApi->CreateSaveObject(szFile, g_FileFormat, &pxofSave);
  5334.     if (FAILED(hr))
  5335.     {
  5336.         cout << "AddScene(): Could not create save object." << endl;
  5337.         goto e_Exit;
  5338.     }
  5339.  
  5340.  
  5341.     // save templates
  5342.     hr = pxofSave->SaveTemplates(3, g_aIds);
  5343.     if (FAILED(hr))
  5344.     {
  5345.         cout << "AddScene(): Could not save templates.";
  5346.         goto e_Exit;
  5347.     }
  5348.  
  5349.  
  5350.     // save file data to the file
  5351.  
  5352.     // first create the SCENE_ROOT Frame
  5353.     hr = pxofSave->CreateDataObject(TID_D3DRMFrame, SCENE_ROOT, NULL, 0, NULL, &pRootFrameObject);
  5354.     if (FAILED(hr))
  5355.     {
  5356.         cout << "AddScene(): Could not create pRootFrameObject." << endl;
  5357.         goto e_Exit;
  5358.     }
  5359.  
  5360.  
  5361.     // next create the SCENE_ROOT FrameTransformMatrix as the Identity 
  5362.     hr = pxofSave->CreateDataObject(TID_D3DRMFrameTransformMatrix, NULL, NULL, 16 * sizeof(float), rgfIdentity, &pRootTransformObject);
  5363.     if (FAILED(hr))
  5364.     {
  5365.         cout << "AddScene(): Could not create pRootTransformObject." << endl;
  5366.         goto e_Exit;
  5367.     }
  5368.  
  5369.  
  5370.     hr = pRootFrameObject->AddDataObject(pRootTransformObject);
  5371.     if (FAILED(hr))
  5372.     {
  5373.         cout << "AddScene(): Could not add pRootTransformObject to pRootFrameObject." << endl;
  5374.         goto e_Exit;
  5375.     }
  5376.  
  5377.  
  5378.     cout << endl << "Loading scene..." << endl;
  5379.  
  5380.     for (; !itDag.isDone() && itDag.depth() <= 1; itDag.next())
  5381.     {
  5382.         MDagPath dagPath;
  5383.  
  5384.         stat = itDag.getPath(dagPath);
  5385.         if (!stat)
  5386.         {
  5387.             cout << "WARNING: Ignoring shape because could not get path to shape." << endl;
  5388.             continue;
  5389.         }
  5390.  
  5391. #ifdef NO_INTERMEDIATE_OBJECTS
  5392.         if (MFnDagNode(dagPath).isIntermediateObject()) 
  5393.             continue;
  5394. #endif
  5395.  
  5396.         hr = AddShape(dagPath, true, pRootFrameObject, pxofSave);
  5397.         if (FAILED(hr))
  5398.             cout << "AddScene(): Could not add top level shape." << endl;
  5399.     }
  5400.  
  5401.     cout.flush();
  5402.     cout << "Writing scene data...";
  5403.     cout.flush();
  5404.  
  5405.     hr = pxofSave->SaveData(pRootFrameObject);
  5406.     if (FAILED(hr))
  5407.     {
  5408.         cout << "AddScene(): Could not save scene data to file." << endl;
  5409.         goto e_Exit;
  5410.     }
  5411.  
  5412.     cout << "DONE!" << endl;
  5413.     cout.flush();
  5414.  
  5415.  
  5416.     
  5417.     if (!g_bExportAnimation) 
  5418.         goto e_Exit;
  5419.  
  5420.     hr = pxofSave->CreateDataObject(TID_D3DRMAnimationSet, NULL, NULL, 0, NULL, &pAnimSetObject);
  5421.     if (FAILED(hr))
  5422.     {
  5423.         cout << "AddScene(): Could not create pAnimSetObject." << endl;
  5424.         goto e_Exit;
  5425.     }
  5426.  
  5427.     cout << "Loading animations..." << endl;
  5428.     cout.flush();
  5429.  
  5430.     if (g_bKeyframeAnimation)
  5431.         hr = LoadKeyframedAnims(&nAnims, &aAnims);
  5432.     else
  5433.         hr = LoadFixedStepAnims(&nAnims, &aAnims);
  5434.     if (FAILED(hr))
  5435.     {
  5436.         cout << "AddScene(): Could not save animations." << endl;
  5437.         goto e_Exit;
  5438.     }
  5439.  
  5440.     cout << "\t" << nAnims << " anim(s) loaded." << endl;
  5441.  
  5442.     cout << "Writing animations...";
  5443.     cout.flush();
  5444.  
  5445.     for (iAnim = 0; iAnim < nAnims; iAnim++)
  5446.     {
  5447.         hr = AddAnim(aAnims + iAnim, pAnimSetObject, pxofSave);
  5448.  
  5449.         if (FAILED(hr))
  5450.         {
  5451.             cout << "AddScene(): Could not add an animation." << endl;
  5452.             continue;
  5453.         }
  5454.     }
  5455.  
  5456.     cout << "DONE!" << endl;
  5457.     cout.flush();
  5458.  
  5459.     hr = pxofSave->SaveData(pAnimSetObject);
  5460.     if (FAILED(hr))
  5461.     {
  5462.         cout << "AddScene(): Could not save animation data to file." << endl;
  5463.         goto e_Exit;
  5464.     }
  5465.  
  5466.     
  5467.  
  5468.  
  5469. e_Exit:
  5470.  
  5471.     // turn on previously visible objects
  5472.     for (iPath = 0; iPath < VisiblePaths.length(); iPath++)
  5473.     {
  5474.         MPlug Visibility;
  5475.         MFnDagNode fnDag;
  5476.         
  5477.         stat = fnDag.setObject(VisiblePaths[iPath]);
  5478.         if (!stat)
  5479.             continue;
  5480.  
  5481.         Visibility = fnDag.findPlug("visibility", &stat);
  5482.         if (!stat)
  5483.             continue;
  5484.  
  5485.         stat = Visibility.setValue(true);
  5486.         if (!stat)
  5487.             continue;
  5488.     }
  5489.  
  5490.     if (pRootFrameObject)
  5491.         pRootFrameObject->Release();
  5492.  
  5493.     if (pRootTransformObject)
  5494.         pRootTransformObject->Release();
  5495.  
  5496.     if (pAnimSetObject)
  5497.         pAnimSetObject->Release();
  5498.  
  5499.  
  5500.     if (pxofSave) 
  5501.         pxofSave->Release();
  5502.  
  5503.     if (pxofApi)
  5504.         pxofApi->Release();
  5505.  
  5506.  
  5507.     cout << endl;
  5508.  
  5509.     if (FAILED(hr))
  5510.         cout << "There were errors.";
  5511.     else 
  5512.         cout << "Completed successfully.";
  5513.  
  5514.     cout << endl << endl << "REMARKS:" << endl;
  5515.  
  5516. #ifdef ALWAYS_TESSELATE_NURBS
  5517.     cout << " - NURBS surfaces are currently always tesselated." << endl;
  5518. #endif
  5519.  
  5520.     if (!g_bExportPatches)
  5521.         cout << " - When a NURBS surface is tesselated, it loses its material and skinning info." << endl;
  5522.  
  5523.     if (!itIkEffectors.isDone())
  5524.     {
  5525.         cout << " - IkEffector nodes were found.  This will probably affect skinning info." << endl;
  5526.         cout << "   Please delete or disable IK nodes and retry for better results." << endl;
  5527.     }
  5528.  
  5529.     cout << " - PolyFaceSmoothing AFTER skinning will lead to bad results." << endl;
  5530.     cout << "   (since the vertices added as a result of PolyFaceSmoothing will have no skin-weights.)" << endl;
  5531.     cout << "...................................................." << endl << endl;
  5532.  
  5533.  
  5534.     
  5535.     cout.flush();
  5536.  
  5537.     delete[] aAnims;
  5538.  
  5539.     return hr;
  5540. }
  5541.  
  5542.  
  5543.  
  5544.  
  5545.  
  5546. void    ParseOptions
  5547.         (
  5548.             MString    msOptions
  5549.         ) 
  5550. {
  5551.     if (msOptions.length() > 0) 
  5552.     {
  5553.         MStringArray    optionList;
  5554.  
  5555.         msOptions.split(';', optionList);
  5556.  
  5557.         // break out all the options.
  5558.         for (int iOption = 0; iOption < (int)optionList.length(); iOption++) 
  5559.         {
  5560.             MStringArray    theOption;
  5561.  
  5562.             optionList[iOption].split('=', theOption);
  5563.  
  5564.             if (theOption.length() > 1) 
  5565.             {
  5566.                 if (theOption[0] == "fileFormat") 
  5567.                 {
  5568.                     if (theOption[1] == "binary") 
  5569.                     {
  5570.                         g_FileFormat    = DXFILEFORMAT_BINARY;
  5571.                     }
  5572.                     else if (theOption[1] == "compressed") 
  5573.                     {
  5574.                         g_FileFormat    = DXFILEFORMAT_COMPRESSED;
  5575.                     }
  5576.                     else    // "text" 
  5577.                     {    
  5578.                         g_FileFormat    = DXFILEFORMAT_TEXT;
  5579.                     }
  5580.                 }
  5581.                 else if (theOption[0] == "exportAnimation") 
  5582.                 {
  5583.                     if (theOption[1] == "false") 
  5584.                     {
  5585.                         g_bExportAnimation    = false;
  5586.                     }
  5587.                     else     // "true"
  5588.                     {
  5589.                         g_bExportAnimation    = true;
  5590.                     }
  5591.                 }
  5592.                 else if (theOption[0] == "keyframeAnimation") 
  5593.                 {
  5594.                     if (theOption[1] == "false") 
  5595.                     {
  5596.                         g_bKeyframeAnimation    = false;
  5597.                     }
  5598.                     else     // "true"
  5599.                     {
  5600.                         g_bKeyframeAnimation    = true;
  5601.                     }
  5602.                 }
  5603.                 else if (theOption[0] == "animateEverything") 
  5604.                 {
  5605.                     if (theOption[1] == "false") 
  5606.                     {
  5607.                         g_bAnimateEverything    = false;
  5608.                     }
  5609.                     else     // "true"
  5610.                     {
  5611.                         g_bAnimateEverything    = true;
  5612.                     }
  5613.                 }
  5614.                 else if (theOption[0] == "frameStep") 
  5615.                 {
  5616.                     g_iFrameStep    = theOption[1].asInt();
  5617.                 }
  5618.                 else if (theOption[0] == "flipU") 
  5619.                 {
  5620.                     if (theOption[1] == "true") 
  5621.                     {
  5622.                         g_iFlipU    = -1;
  5623.                     }
  5624.                     else     // "false"
  5625.                     {
  5626.                         g_iFlipU    = 1;
  5627.                     }
  5628.                 }
  5629.                 else if (theOption[0] == "flipV") 
  5630.                 {
  5631.                     if (theOption[1] == "true") 
  5632.                     {
  5633.                         g_iFlipV    = 1;
  5634.                     }
  5635.                     else     // "false"
  5636.                     {
  5637.                         g_iFlipV    = -1;
  5638.                     }
  5639.                 }
  5640.                 else if (theOption[0] == "exportPatches") 
  5641.                 {
  5642.                     if (theOption[1] == "true") 
  5643.                     {
  5644.                         g_bExportPatches    = true;
  5645.                     }
  5646.                     else     // "false"
  5647.                     {
  5648.                         g_bExportPatches    = false;
  5649.                     }
  5650.                 }
  5651.                 else if (theOption[0] == "relTexFilename")
  5652.                 {
  5653.                     if (theOption[1] == "true") 
  5654.                     {
  5655.                         g_bRelativeTexFile    = true;
  5656.                     }
  5657.                     else     // "false"
  5658.                     {
  5659.                         g_bRelativeTexFile    = false;
  5660.                     }
  5661.                 }
  5662.             }
  5663.         }
  5664.     }
  5665. }
  5666.  
  5667.  
  5668.  
  5669. MStatus    xfileTranslator::writer
  5670.         (    // parameters
  5671.             const MFileObject& file, 
  5672.             const MString& sOptions, 
  5673.             MPxFileTranslator::FileAccessMode mode
  5674.         ) 
  5675. {
  5676.     g_Arrays.Initialize();
  5677.  
  5678.     ParseOptions(sOptions);
  5679.  
  5680.     MString    sFile    = file.fullName();
  5681.  
  5682.     int        iExt    = sFile.rindex('.');
  5683.     MString    sExt    = sFile.substring(iExt, sFile.length() - 1);
  5684.  
  5685.     sFile    = (sExt == ".x" || sExt == ".X") ? sFile : (sFile + ".x");
  5686.  
  5687.     g_AddedPaths.clear();
  5688.  
  5689.     AddScene(sFile.asChar());
  5690.  
  5691.     g_Arrays.CleanUp();
  5692.  
  5693.     g_iCount = 0;
  5694.  
  5695.     return MS::kSuccess;
  5696. }
  5697.  
  5698.  
  5699.  
  5700.  
  5701.  
  5702. MStatus    initializePlugin 
  5703.         (    
  5704.             MObject    obj
  5705.         ) 
  5706. {
  5707.     MStatus stat = MS::kSuccess;
  5708.     char            version[256];
  5709.  
  5710.     strcpy(version, "0.3");                // plug-in version
  5711.     strcat(version, ".");
  5712.     strcat(version, DtAPIVersion());
  5713.     
  5714.     MFnPlugin plugin(obj, "XFile Translator for Maya", version, "Any");
  5715.  
  5716.     // register the translator
  5717.     stat = plugin.registerFileTranslator("XFile", "xfileTranslator.rgb", xfileTranslator::creator, "xfileTranslatorOpts", "", true);
  5718.     if (!stat)
  5719.         stat.perror("registerFileTranslator");
  5720.  
  5721.     return stat;
  5722. }
  5723.  
  5724.  
  5725. MStatus    uninitializePlugin
  5726.         (    
  5727.             MObject obj
  5728.         ) 
  5729. {
  5730.     MStatus         status;
  5731.     MFnPlugin       plugin(obj);
  5732.  
  5733.     status = plugin.deregisterFileTranslator("XFile");
  5734.  
  5735.     if (!status)
  5736.         status.perror("deregisterFileTranslator");
  5737.  
  5738.     return status;
  5739. }
  5740.  
  5741.  
  5742.  
  5743.  
  5744. /*
  5745.  
  5746. HRESULT    LoadFixedStepAnims
  5747.         (
  5748.             SAnim*    rgAnims
  5749.         )
  5750. {
  5751.     HRESULT    hr    = S_OK;
  5752.  
  5753.     cout << "\treading at intervals of " << g_iFrameStep << " frame(s)" << endl;
  5754.  
  5755.     // calculate the frames per second
  5756.     int    iFPS    = 1;
  5757.  
  5758.     switch(MTime::uiUnit()) 
  5759.     {
  5760.         case MTime::kSeconds:        // 1 fps
  5761.             iFPS    = 1;
  5762.             break;
  5763.         case MTime::kMilliseconds:    // 1000 fps
  5764.             iFPS    = 1000;
  5765.             break;
  5766.         case MTime::kGames:            // 15 fps
  5767.             iFPS    = 15;
  5768.             break;
  5769.         case MTime::kFilm:            // 24 fps
  5770.             iFPS    = 24;
  5771.             break;
  5772.         case MTime::kPALFrame:        // 25 fps
  5773.             iFPS    = 25;
  5774.             break;
  5775.         case MTime::kNTSCFrame:        // 30 fps
  5776.             iFPS    = 30;
  5777.             break;
  5778.         case MTime::kShowScan:        // 48 fps
  5779.             iFPS    = 48;
  5780.             break;
  5781.         case MTime::kPALField:        // 50 fps
  5782.             iFPS    = 50;
  5783.             break;
  5784.         case MTime::kNTSCField:        // 60 fps
  5785.             iFPS    = 60;
  5786.             break;
  5787.         default:
  5788.             iFPS    = 1;
  5789.             break;
  5790.     };
  5791.  
  5792.     float fTimeFactor    = 3600.0f / (float)iFPS;
  5793.  
  5794.  
  5795.     MTime    timeStart(MAnimControl::minTime().value(), MTime::uiUnit());
  5796.     MTime    timeEnd(MAnimControl::maxTime().value(), MTime::uiUnit());
  5797.     MTime    timeCurrent(MAnimControl::currentTime().value(), MTime::uiUnit());
  5798.  
  5799.  
  5800.     DtFrameSetStart((int)timeStart.value());
  5801.     DtFrameSetEnd((int)timeEnd.value());
  5802.  
  5803.  
  5804.     int cShapes    = DtShapeGetCount();
  5805.  
  5806.  
  5807.     MIntArray*    rgrgiKeys    = new MIntArray[cShapes];
  5808.  
  5809.  
  5810.     for (int iShape = 0; iShape < cShapes; iShape++) 
  5811.     {
  5812.         rgAnims[iShape].m_szName    = new char[256];
  5813.         rgAnims[iShape].m_nKeys        = 0;
  5814.         rgAnims[iShape].m_aKeys    = new SKey[1 + (DtFrameGetEnd() - DtFrameGetStart() + 1) / g_iFrameStep];
  5815.  
  5816.         g_Arrays.Add(STRING, rgAnims[iShape].m_szName);
  5817.  
  5818.         char* szName;
  5819.  
  5820.         DtShapeGetName(iShape, &szName);
  5821.  
  5822.         strcpy(rgAnims[iShape].m_szName, szName);
  5823.  
  5824.         DtShapeGetTRSAnimKeys(iShape, &rgrgiKeys[iShape]);
  5825.     }
  5826.  
  5827.     for (int iFrame = DtFrameGetStart(); iFrame <= DtFrameGetEnd(); iFrame += g_iFrameStep) 
  5828.     {
  5829.         DtFrameSet(iFrame);
  5830.  
  5831.         for (int iShape = 0; iShape < cShapes; iShape++) 
  5832.         {
  5833.             if (rgrgiKeys[iShape].length() > 0 || g_bAnimateEverything) 
  5834.             {
  5835.                 rgAnims[iShape].m_aKeys[rgAnims[iShape].m_nKeys].m_iFrame    = (int)((float)iFrame * fTimeFactor);
  5836.  
  5837.                 float*    rgfTRS;
  5838.  
  5839.                 DtShapeGetMatrix(iShape, &rgfTRS);
  5840.  
  5841.                 DtMatrixGetTransforms(rgfTRS, 
  5842.                                       rgAnims[iShape].m_aKeys[rgAnims[iShape].m_nKeys].m_afPosition, 
  5843.                                       rgAnims[iShape].m_aKeys[rgAnims[iShape].m_nKeys].m_afScale, 
  5844.                                       rgAnims[iShape].m_aKeys[rgAnims[iShape].m_nKeys].m_afQuaternion, 
  5845.                                       rgAnims[iShape].m_aKeys[rgAnims[iShape].m_nKeys].m_afRotation);
  5846.  
  5847.                 rgAnims[iShape].m_nKeys++;
  5848.             }
  5849.         }
  5850.     }
  5851.  
  5852.     DtFrameSet((int)timeCurrent.value());
  5853.  
  5854.     delete[] rgrgiKeys;
  5855.  
  5856.     return hr;
  5857. }
  5858.  
  5859. */
  5860.  
  5861.  
  5862.  
  5863.  
  5864.  
  5865.  
  5866.  
  5867. /*** TOOLS
  5868.  
  5869.     // print out the attributes of a dependency node
  5870.     for (unsigned iAttr = 0; iAttr < fnNode.attributeCount(); iAttr++) 
  5871.     {
  5872.         MFnAttribute fnAttr(fnNode.attribute(iAttr));
  5873.  
  5874.         cout << fnNode.name() << "." << fnAttr.name() << ": " << fnNode.attribute(iAttr).apiTypeStr() << endl;
  5875.     }
  5876.  
  5877.  
  5878.  
  5879.  
  5880.  
  5881.     // print the node containing the corresponging plug to 'plug'
  5882.     MPlugArray rgPlugs;
  5883.  
  5884.     plug.connectedTo(rgPlugs, true, true);
  5885.  
  5886.     for (int i = 0; i < (int)rgPlugs.length(); i++) 
  5887.     {
  5888.         MFnDependencyNode fnNode(rgPlugs[i].node());
  5889.  
  5890.         cout << fnNode.name() << "\t" << rgPlugs[i].name() << endl;
  5891.     }
  5892.  ***/